Canvas Drag and Drop Less Ephemeral Tutorial

Canvas Drag and Drop Less Ephemeral Tutorial

Canvas Drag and Drop Less Ephemeral Tutorial

We’re bucking the trend, today, “offering less” but “producing more”, we’re hoping, on top of the progress of yesterday’s Canvas Drag and Drop Ephemeral Tutorial ….

  • adding totaking from an “internal use only” level of ephemeralness which only offered an individual user view of canvas based Animated GIF style slide creation work as an Animated GIF presentation in their individually presented popup window … to …
  • adding to above a new 📧 Email emoji sharing (and “caring”) button within that popup window presentation … that if clicked …
    1. prompts the user as per …

      var huhe=prompt("Please enter email address to share Animated GIF style presentation with. Append a hashtagged delay between slides in milliseconds that is not 4000 optionally.", "");
    2. allows an “a” “mailto:” link’s “href” attribute reflect any hashtagged delay you specified …

      if (huhe.indexOf("#") != -1) {
      document.getElementById("aemail").href=document.getElementById("aemail").href.replace(encodeURIComponent("delay=4000"),encodeURIComponent("delay=" + huhe.split("#")[1])); huhe=huhe.split("#")[0];
      }
    3. allows an “a” “mailto:” link’s “href” attribute reflect any emailee you specified …

      if (huhe.indexOf("@") != -1) {
      document.getElementById("aemail").href=document.getElementById("aemail").href.replace(":?", ":" + huhe + "?"); document.getElementById("aemail").click();
      }
    4. and if all ritchy ditch …

      if (huhe.indexOf("@") != -1) {
      document.getElementById("aemail").click();
      }
    5. clicks the “a” “mailto:” link, passing control over to your default email client software to present you with an email body presentation webpage by which you can click a Send icon to send that largely hashtagged data email to an email recipient (ie. emailee)

… in the changed user_of_signature_signature.htm User of Signature Signature inhouse canvas graphic data web application, helped out by ever more changing helperer outerer htmlemail.html (just HTML and Javascript and hashtagging) of recent times, gradually replacing work that used to be a PHP thaing via emailhtml.php associated with RJM Programming domain’s email server fed by PHP mail command based email messages, now more in favour of hashtagging methodologies using “a” “mailto:” links, where we are only talking “clientside” with the logic, and the data length restrictions are not as severe.

Today’s animated GIF presentation, hence, is recreatable

Back to top

Did you know?

When it comes to email (and SMS for that matter) creation logic, occasionally, we find, you need to double encode … we kid you not! We needed to today, as you see below …


var popupemailfunction='';

if (popupemailfunction == '') {
popupemailfunction=' function dopopupemail() { var huhe=prompt("Please enter email address to share Animated GIF style presentation with. Append a hashtagged delay between slides in milliseconds that is not 4000 optionally.", ""); if (huhe == null) { huhe=""; } if (huhe.indexOf("@") != -1) { if (huhe.indexOf("#") != -1) { document.getElementById("aemail").href=document.getElementById("aemail").href.replace(encodeURIComponent("delay=4000"),encodeURIComponent("delay=" + huhe.split("#")[1])); huhe=huhe.split("#")[0]; } document.getElementById("aemail").href=document.getElementById("aemail").href.replace(":?", ":" + huhe + "?"); document.getElementById("aemail").click(); } } ';
}
htmlis='<ht' + 'ml><he' + 'ad><title>Inhouse Animated GIF style presentation ...</title><scri' + 'pt type=text/javascript> var dataih="", oneround=false, curslides=0, thislag=0; ' + popupemailfunction + ' function shows() { thislag=1; curslides=window.opener.getdzlen(); for (var ii=0; ii<curslides; ii++) { if (ii == 0) { if (!oneround) { oneround=true; document.getElementById("semail").style.display="block"; } setTimeout(function() { dataih=window.opener.getdzfirst(); if (document.getElementById("aemail").href.indexOf(encodeURIComponent(encodeURIComponent(dataih.split("url(")[1].split(")")[0].replace(/\"\;/g,"").replace(/\"/g,"")))) == -1) { document.getElementById("aemail").href+=encodeURIComponent(encodeURIComponent(dataih.split("url(")[1].split(")")[0].replace(/\"\;/g,"").replace(/\"/g,""))); } document.getElementById("ptarget").innerHTML=dataih; }, thislag); } else { setTimeout(function() { dataih=window.opener.getdznext(); if (document.getElementById("aemail").href.indexOf(encodeURIComponent(encodeURIComponent(dataih.split("url(")[1].split(")")[0].replace(/\"\;/g,"").replace(/\"/g,"")))) == -1) { document.getElementById("aemail").href+=encodeURIComponent(encodeURIComponent(dataih.split("url(")[1].split(")")[0].replace(/\"\;/g,"").replace(/\"/g,""))); } document.getElementById("ptarget").innerHTML=dataih; }, thislag); } thislag+=4000; } setTimeout(shows, thislag); } setTimeout(shows,5000); </scr' + 'ipt></he' + 'ad><bo' + 'dy data-onload="setTimeout(shows,5000);"><div id=ptarget></div><br><button title="Share via Email" id=semail style=display:none; onclick="dopopupemail();">&#128231;</button><a target=top id=aemail style=display:none; href="mailto:?subject=Animated%20GIF%20presentation&body=' + encodeURIComponent('https://www.rjmprogramming.com.au/htmlemail.html?delay=4000#') + '">Email</a></bo' + 'dy></ht' + 'ml>';

The pattern of when (we need to do this) remains a bit mysterious to us, but if we ever nail down the pattern, am sure you’ll hear about it! The good side to solving via “double encoding” means is that you can easily see where the wall needs to be repaired straight in front of you … in real time?!


Previous relevant Canvas Drag and Drop Ephemeral Tutorial is shown below.

Canvas Drag and Drop Ephemeral Tutorial

Canvas Drag and Drop Ephemeral Tutorial

Onto yesterday’s Canvas Drag and Drop Primer Tutorial‘s …

  • proof of concept feel to being able to drag and drop via the canvas element … today we have …
  • proof of concept ideas regarding future sharing and collaboration aspects to this Drag and Drop where we start with our “ephemeral” inhouse popup window version of what we hope to offer, in future, for users to share with email recipients

And the other progress was another “drag” friend for the canvas element, allowing that textarea element (now with ondragstart=”dragstart(event);” draggable=true attribution) down the bottom right also be “draggable” (to create the textarea wording on a white backgrounded slide “Drop Zone” result when dragged there) for our …

  • “Drop Zone” for non-mobile … and …
  • “Click Zone” for mobile

… platforms. The drag and drop functionality related global variables now go …


var dz='Drop Zone';
if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
dz='Click Zone';
}
var dzslides=[], dzo=null, dzcnt=0;
var lastdrop='', lastelem=null, wasmt='0px';

… and the Drag and Drop logic now goes


function dragstart(ev) {
lastelem=ev.target;
if (('' + ev.target.outerHTML).indexOf('<textarea') == 0) {
ev.dataTransfer.setData("text/plain", ev.target.value);
} else {

ev.dataTransfer.setData("text/plain", document.getElementById('topcanvas').toDataURL());
}
}

function dragover(ev) {
ev.preventDefault();
}

function drop(ev) {
var prefixingih='', mtdone=false, opsty='';
if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) {
if (('' + lastelem.outerHTML).indexOf('<textarea') == 0) {
lastdrop=lastelem.value;
while (lastdrop.indexOf(String.fromCharCode(10)) != -1) {
lastdrop=lastdrop.replace(String.fromCharCode(10),'<br>');
}
prefixingih='<span style=background-color:white;>' + lastdrop + '</span><br><br>';
opsty=' style="opacity:0.3;" ';
lastdrop=dzslides[0];
document.getElementById('target').innerHTML = dzslides[0];
if (document.getElementById('tarbut')) {
mtdone=true;
document.getElementById('tarbut').style.marginTop='0px';
}
} else {

document.getElementById('target').innerHTML = document.getElementById('topcanvas').toDataURL();
lastdrop=document.getElementById('target').innerHTML;
if (document.getElementById('tarbut')) {
mtdone=true;
document.getElementById('tarbut').style.marginTop=wasmt;
}
}
} else {
if (('' + lastelem.outerHTML).indexOf('<textarea') == 0) {
lastdrop=lastelem.value;
while (lastdrop.indexOf(String.fromCharCode(10)) != -1) {
lastdrop=lastdrop.replace(String.fromCharCode(10),'<br>');
}
prefixingih='<span style=background-color:white;>' + lastdrop + '</span><br><br>';
opsty=' style="opacity:0.3;" ';
lastdrop=dzslides[0];
document.getElementById('target').innerHTML = dzslides[0];
if (document.getElementById('tarbut')) {
mtdone=true;
document.getElementById('tarbut').style.marginTop='0px';
}
} else {
ev.target.innerHTML = ev.dataTransfer.getData("text");
lastdrop=ev.target.innerHTML;
if (document.getElementById('tarbut')) {
mtdone=true;
document.getElementById('tarbut').style.marginTop=wasmt;
}
}
}

document.getElementById('topcanvas').setAttribute('draggable','false');
document.getElementById('target').innerHTML=prefixingih + '<button ' + opsty + ' id=tarbut onclick=\" event.stopPropagation(); if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) { drop(document.getElementById(' + "'target'" + ')); } else { document.getElementById(' + "'topcanvas').setAttribute('draggable','true'); document.getElementById('target').innerHTML=''; if (navigator.userAgent.match(/Android|BlackBerry|iPhone|iPad|iPod|Opera Mini|IEMobile/i)) { document.getElementById('starbut').style.zIndex='50'; } else { document.getElementById('starbut').style.marginTop='-50px'; document.getElementById('starbut').style.zIndex='-50'; } document.getElementById('starbut').innerHTML='" + dz + "'" + '; } \">' + dz + ' for Canvas After Click</button>';
if (document.getElementById('tarbut') && !mtdone) {
mtdone=true;
if (prefixingih != '') {
document.getElementById('tarbut').style.marginTop='0px';
} else {
document.getElementById('tarbut').style.marginTop=wasmt;
}
}

document.getElementById('starbut').innerHTML='';
var rectis=document.getElementById('target').getBoundingClientRect();
if (document.getElementById('mydbut')) {
rectis=document.getElementById('mydbut').getBoundingClientRect();
} else if (document.getElementById('tarbut')) {
rectis=document.getElementById('tarbut').getBoundingClientRect();
}
document.getElementById('target').setAttribute('data-mt','' + eval(-30 + eval('' + rectis.width)));
document.getElementById('target').style.backgroundColor='white';
document.getElementById('target').style.height='' + rectis.width + 'px';
document.getElementById('target').style.backgroundImage='url(' + lastdrop + ')';
document.getElementById('target').style.backgroundSize='contain';
document.getElementById('target').style.backgroundRepeat='no-repeat';
if (document.getElementById('topdragstyle').innerHTML == '' && prefixingih == '') {
wasmt='' + eval(-30 + eval('' + rectis.width)) + 'px';
document.getElementById('tarbut').style.marginTop=wasmt;
//var rectistb=document.getElementById('tarbut').getBoundingClientRect();
//document.getElementById('topdragstyle').innerHTML='<style> #tarbut { position:absolute; left:' + rectistb.left + 'px; top:' + eval(eval(0 * eval(-30 + eval('' + rectis.width))) + eval('' + rectistb.top)) + 'px; margin-top:0px !important; } </style>';
}
if (document.getElementById('tarbut')) {
dzslides.push(document.getElementById('target').outerHTML.replace(document.getElementById('tarbut').outerHTML,''));
} else {
dzslides.push(document.getElementById('target').outerHTML);
}
if (eval('' + dzslides.length) > 2) {
var htmlis='';
if (dzo == null) {
dzo=window.open('','_blank','top=200,left=200,width=300,height=300');
htmlis='<ht' + 'ml><he' + 'ad><title>Inhouse Animated GIF style presentation ...</title><scri' + 'pt type=text/javascript> var curslides=0, thislag=0; function shows() { thislag=1; curslides=window.opener.getdzlen(); for (var ii=0; ii<curslides; ii++) { if (ii == 0) { setTimeout(function() { document.getElementById("ptarget").innerHTML=window.opener.getdzfirst(); }, thislag); } else { setTimeout(function() { document.getElementById("ptarget").innerHTML=window.opener.getdznext(); }, thislag); } thislag+=4000; } setTimeout(shows, thislag); } setTimeout(shows,5000); </scr' + 'ipt></he' + 'ad><bo' + 'dy data-onload="setTimeout(shows,5000);"><div id=ptarget></div></bo' + 'dy></ht' + 'ml>';
dzo.document.write(htmlis);
dzo.document.title='Inhouse Animated GIF style presentation ...';
} //else if (dzo.closed) {
// dzo=window.open('','_blank','top=200,left=200,width=300,height=300');
// htmlis='<ht' + 'ml><he' + 'ad><scri' + 'pt type=text/javascript> var curslides=0, thislag=0; function shows() { thislag=1; curslides=window.opener.getdzlen(); for (var ii=0; ii<curslides; ii++) { if (ii == 0) { setTimeout(function() { document.getElementById("ptarget").innerHTML=window.opener.getdzfirst(); }, thislag); } else { setTimeout(function() { document.getElementById("ptarget").innerHTML=window.opener.getdznext(); }, thislag); } thislag+=4000; } setTimeout(shows, thislag); } setTimeout(shows,5000); </scr' + 'ipt></he' + 'ad><bo' + 'dy data-onload="setTimeout(shows,5000);"><div id=ptarget></div></bo' + 'dy></ht' + 'ml>';
// dzo.document.write(htmlis);
//}
}

}

function getdzlen() {
return eval('' + dzslides.length);
}

function getdzfirst() {
var iwhich=0;
dzcnt=1;
if (iwhich == 0) {
//alert(document.getElementById('target').outerHTML);
var pone=document.getElementById('target').outerHTML.split('>')[0].replace('url(' + document.getElementById('target').outerHTML.split('url(')[1].split(')')[0] + ')', 'url(' + dzslides[iwhich] + ')');
return pone + '></div>';
}
if (('' + dzslides[iwhich]) == 'undefined') { return ''; }
return dzslides[iwhich];
}

function getdznext() {
var iwhich=dzcnt;
dzcnt++;
if (iwhich == 0) {
var pone=document.getElementById('target').outerHTML.split('>')[0].replace('url(' + document.getElementById('target').outerHTML.split('url(')[1].split(')')[0] + ')', 'url(' + dzslides[iwhich] + ')');
return pone + '></div>';
}
if (('' + dzslides[iwhich]) == 'undefined') { return ''; }
return dzslides[iwhich];
}

function getdz(iwhich) {
if (iwhich == 0) {
//alert(document.getElementById('target').outerHTML);
var pone=document.getElementById('target').outerHTML.split('>')[0].replace('URL(' + document.getElementById('target').outerHTML.split('URL(')[1].split(')')[0] + ')', 'URL(' + dzslides[iwhich] + ')');
return pone + '></div>';
}
if (('' + dzslides[iwhich]) == 'undefined') { return ''; }
return dzslides[iwhich];
}


setTimeout(function() {
if (elem) {
if (eval('' + dzslides.length) == 0) {
dzslides.push(elem.toDataURL());
}
} else if (document.getElementById('topcanvas')) {
if (eval('' + dzslides.length) == 0) {
dzslides.push(document.getElementById('topcanvas').toDataURL());
}
}
}, 5000);

… in the changed user_of_signature_signature.htm User of Signature Signature inhouse canvas graphic data web application.


Previous relevant Canvas Drag and Drop Primer Tutorial is shown below.

Canvas Drag and Drop Primer Tutorial

Canvas Drag and Drop Primer Tutorial

It’s time. It really is. It’s time to revisit the “User of Signature Signature” web application using the HTML5 canvas element to create and share graphical data, that we last dealt with when we presented Canvas Sharing via Email Hashtagging Tutorial.

Why? Well, we want to combine …

  • canvas … graphical data … to start with … with …
  • drag and drop methodologies

… to add to the functionality of our “User of Signature Signature” web application. Today is the “proof of concept” day because there are two conflicting issues for us …

  • scribble functionality on a canvas element … is at odds with …
  • the draggable=true attribute usage crucial to getting Drag and Drop methodologies to kick in

You may have noticed with the “User of Signature Signature” web application it starts ready to scribble on the canvas straight away. And do you think we can resist that, as we test it?! No way!

That same steadiness to that canvas, as it is set up to resist “internal movement” also stops it being draggable alas … depending how you look at it.

And so we thought about this and came up with …

  1. do the usual this useful link suggests about setting up the canvas element for Drag and Drop …

    <canvas ondragstart="dragstart(event);" draggable=truefalse title="Ready for you to create your canvas 🎨 content above any signature 💳 panel ..." id="topcanvas" width=850 height=600 style="background-color:white; position: absolute; top:0; left:0; border-bottom:5px solid yellow; border-right:5px solid blue;"></canvas>

    … except start the draggable attribute with value false … and team this with …
  2. new Drop Zone HTML element helpers …

    <div id="target" ondrop="drop(event);" ondragover="dragover(event);" data-mt="0" style="vertical-align:bottom;display:block;background-color:transparent;">
    <button id=mydbut onclick=" document.getElementById('topcanvas').setAttribute('draggable','true'); document.getElementById('target').innerHTML='<span id=tarbut style=margin-top:' + document.getElementById('target').getAttribute('data-mt') + 'px;>Drop Zone</span>'; ">Drop Zone for Canvas After Click</button>
    </div>
    <span id=starbut></span>

    … and …
  3. programmatically controlled HTML button element click logic …

    var lastdrop='';

    function dragstart(ev) {
    ev.dataTransfer.setData("text/plain", document.getElementById('topcanvas').toDataURL());
    }

    function dragover(ev) {
    ev.preventDefault();
    }

    function drop(ev) {
    ev.target.innerHTML = ev.dataTransfer.getData("text");
    lastdrop=ev.target.innerHTML;
    document.getElementById('topcanvas').setAttribute('draggable','false');
    document.getElementById('target').innerHTML='<button id=tarbut onclick=\" document.getElementById(' + "'topcanvas').setAttribute('draggable','true'); document.getElementById('target').innerHTML=''; document.getElementById('starbut').style.marginTop='-50px'; document.getElementById('starbut').style.zIndex='-50'; document.getElementById('starbut').innerHTML='Drop Zone'" + '; \">Drop Zone for Canvas After Click</button>';
    document.getElementById('starbut').innerHTML='';
    var rectis=document.getElementById('target').getBoundingClientRect();
    if (document.getElementById('mydbut')) {
    rectis=document.getElementById('mydbut').getBoundingClientRect();
    } else if (document.getElementById('tarbut')) {
    rectis=document.getElementById('tarbut').getBoundingClientRect();
    }
    document.getElementById('target').setAttribute('data-mt','' + eval(-30 + eval('' + rectis.width)));
    document.getElementById('target').style.height='' + rectis.width + 'px';
    document.getElementById('target').style.backgroundImage='URL(' + lastdrop + ')';
    document.getElementById('target').style.backgroundSize='contain';
    document.getElementById('target').style.backgroundRepeat='no-repeat';
    if (document.getElementById('topdragstyle').innerHTML == '') {
    document.getElementById('tarbut').style.marginTop='' + eval(-30 + eval('' + rectis.width)) + 'px';
    //var rectistb=document.getElementById('tarbut').getBoundingClientRect();
    //document.getElementById('topdragstyle').innerHTML='<style> #tarbut { position:absolute; left:' + rectistb.left + 'px; top:' + eval(eval(0 * eval(-30 + eval('' + rectis.width))) + eval('' + rectistb.top)) + 'px; margin-top:0px !important; } </style>';
    }
    }

    … to toggle between the modes of use

… in the changed user_of_signature_signature.htm User of Signature Signature inhouse canvas graphic data web application.

Like we say, “proof of concept” (and mobile platforms need more thinking, so see Stop Press below), today, ahead of “usefulness” to come!

Stop Press

We know (again, via this useful link) from simple canvas scenarios Drag and Drop can work for mobile, but we couldn’t get it to work for our canvas used for scribbling and other annotation purposes. And so, in our further changed user_of_signature_signature.htm User of Signature Signature inhouse canvas graphic data web application we got some “onclick” event replacement code working for mobile platforms involving less work for the user. Some may see this as an enhancement, but personally, we’re awfully fond of Drag and Drop even with the slightly greater bother. We just think it helps a user clarify in their minds what they are doing, and not necessarily blithely clicking away with impunity.


Previous relevant Canvas Sharing via Email Hashtagging Tutorial is shown below.

Canvas Sharing via Email Hashtagging Tutorial

Canvas Sharing via Email Hashtagging Tutorial

We’re regular “tweakers” (for example, with Canvas via Image Web Share API Photo Postcard Tutorial) of what we call the …

  • canvas … based …
  • signatures … possible …
  • scribble … or …
  • discrete click … creating …
  • annotation … friendly …

… “graphics sharing” web application “User of Signature Signature”. And with us, more and more …

  • decoupling our PHP mail sharing conduits … in favour of …
  • “a” link “mailto:” email (and sometimes “sms:” SMS) communication conduits … now making use of …
  • hashtagging … parts to URLs used …

… because this methodology has fewer data limits, it being a “clientside” only (for the main part) means of sharing data. Today, we’re looking into this.

Happily, for this work, “the lynchpin” is some “signature_signature.js” external Javascript, which is all that needs tweaking to make these changes.

Previously, we’d relied, more, on “signature_signature.php” PHP, which oversaw our previous interfacing to the mail server up at the RJM Programming domain via the PHP mail function.

Now, the user sends their own emails with their own email client software, and emails contain one long body URL string where …

  • canvas … element’s …
  • [canvasElement].toDataURL(‘image/jpeg’, 0.7) … means by which a …
  • data URI representation of the graphical data

… can be hashtagged into that long body URL string. If the email recipient clicks this link, our external Javascript …

Reads such incoming data via location.hash

var azx=null, wowowo=null;
var imgbih=('' + ('' + location.hash).replace(/^null/g,'').replace(/^undefined/g,'')).split('img=')[1] ? (decodeURIComponent(('' + location.hash).replace(/^null/g,'').replace(/^undefined/g,'')).split('img=')[1].split('&')[0]).replace(/\ /g,'+') : '';
var passedsubject=location.search.split('subject=')[1] ? decodeURIComponent(location.search.split('subject=')[1].split('&')[0]) : '';
And loaded into canvas and new window …

setTimeout(function(){
if (imgbih != '') {
//alert(imgbih);
if (top.document.getElementById('topcanvas')) {
var xanimg=document.createElement('img');
xanimg.onload=function() {
var tc=top.document.getElementById('topcanvas').getContext('2d');
tc.drawImage(xanimg, 0, 0);
};
xanimg.src=imgbih;
}
var wowowo=window.open('','_blank','top=100,left=100,width=800,height=800');
wowowo.document.write('<html><body style="background:URL(' + "'" + imgbih + "'" + ');background-repeat:no-repeat;"></body></html>');
imgbih='';
if (passedsubject != '') {
wowowo.document.title='' + passedsubject;
}
}
}, 5000);
Before submitting form method=POST to signature_signature.php check out form fields

if (('' + document.getElementById('emailto').value).indexOf('@') != -1 && ('' + document.getElementById('contentto').value).indexOf('data:image/jpeg;base64,') != -1) {
azx=document.createElement("a");
document.body.appendChild(azx);
azx.style = "display: none";
azx.href = 'mailto:' + document.getElementById('emailto').value + ('?subject=' + encodeURIComponent(document.getElementById('subject').value)).replace(/subject\=$/g,'subject=My%20Canvas%20Creation') + '&body=' + encodeURIComponent(top.document.URL.split('?')[0].split('#')[0] + ('?subject=' + encodeURIComponent(document.getElementById('subject').value)).replace(/subject\=$/g,'subject=My%20Canvas%20Creation') + '#img=' + encodeURIComponent(document.getElementById('contentto').value));
azx.click();
} else {

document.getElementById('myform').submit();
}

… to enact fairly simple changes for more stable sharing and collaboration arrangements via a tweaked external Javascript signature_signature.js code used by our signature use in canvas supervisory web application.


Previous relevant Canvas via Image Web Share API Photo Postcard Tutorial is shown below.

Canvas via Image Web Share API Photo Postcard Tutorial

Canvas via Image Web Share API Photo Postcard Tutorial

We discovered, further to yesterday’s Canvas via Image Web Share API Personalization Tutorial, out and about, with an iPhone, that …

Image Input Mode Image Sizing Modus Operandi
URL Actual (canvas resized to image)
Contain (canvas)
Cover (canvas)
Browsing Actual (canvas resized to image)
Contain (canvas)
Cover (canvas)

… of Images to Canvas No Clicking Form Signature Tutorial times was worth refocussing on, regarding the combination of …

  • Browsing … Contain (canvas) … option above … and …
  • Take Photo … mobile device option … which, if followed through on, is more than likely to leave …
  • On the right hand side of the canvas there will be white space suitable to scribble a message to complete your …
  • Postcard … which you can optionally …
  • Share

… and if you are using the https: protocol with the Safari and Google Chrome web browser(s), we can help out more with that last step, being able to make a sharing button show the word “Postcard” …


function checkonyellow() {
var ibuta=[], jbuta=0;
if (safariblurb != '') {
if (document.getElementById('shareurl')) {
if (document.getElementById('shareurl').outerHTML.indexOf('yellow') != -1) {
ibuta=document.getElementsByTagName('input');
for (jbuta=0; jbuta<ibuta.length; jbuta++) {
if (('' + ibuta[jbuta].value) == 'Share URL Link') {
ibuta[jbuta].value='Postcard';
ibuta[jbuta].style.backgroundColor='cyan';
}
}
} else {
setTimeout(checkonyellow, 3000);
}
} else if (parent.document.getElementById('shareurl')) {
if (parent.document.getElementById('shareurl').outerHTML.indexOf('yellow') != -1) {
ibuta=parent.document.getElementsByTagName('input');
for (jbuta=0; jbuta<ibuta.length; jbuta++) {
if (('' + ibuta[jbuta].value) == 'Share URL Link') {
ibuta[jbuta].value='Postcard';
ibuta[jbuta].style.backgroundColor='cyan';
}
}
} else {
setTimeout(checkonyellow, 3000);
}
} else if (top.document.getElementById('shareurl')) {
if (top.document.getElementById('shareurl').outerHTML.indexOf('yellow') != -1) {
ibuta=top.document.getElementsByTagName('input');
for (jbuta=0; jbuta<ibuta.length; jbuta++) {
if (('' + ibuta[jbuta].value) == 'Share URL Link') {
ibuta[jbuta].value='Postcard';
ibuta[jbuta].style.backgroundColor='cyan';
}
}
} else {
setTimeout(checkonyellow, 3000);
}
}
}
}

… to make the procedure …

Postcard via smart device Camera advice …

1. Touch browsing Choose File button that has just appeared.
2. Choose to Take Photo.
3. Consider any zooming in or selfie modes of use in Photo mode.
4. Take photo with Camera app white button, choosing Use Photo or Retake, as required.
5. Scribble any optional messaging in white area to right, or use other discreet touch functionalities.
6. Optionally email off to recipient (as textbox below goes yellow, click email sender button to its left for easier usage).

… more obvious, via the changed external Javascript signature_signature.js code used by our signature use in canvas supervisory web application.


Previous relevant Canvas via Image Web Share API Personalization Tutorial is shown below.

Canvas via Image Web Share API Tutorial

Canvas via Image Web Share API Personalization Tutorial

Yesterday’s Canvas via Imge Web Share API Tutorial‘s Web Share API (so far, on Safari and Google Chrome web browser(s)) image (via canvas) sharing functionality did not have enough privacy for the user, as far as we were concerned. We’re not going in for some two factor authentication level of privacy here, and so we’ve opted for the use of the word “Personalization” in today’s blog posting title.

What we’ve done here is incorporate into the image name (a form of) the IP address of the sender of the image, which the receiver is using (for that extra privacy) as they click the email link, that now involves (a form of) this IP address in its formation.

No surprises here, that we’d have to involve our changed PHP helper signature_signature.php “specialist signature PHP helper” more, getting this solution together.

And no surprises here, that we’d try to involve the web server’s disk areas outside the scope of its (Apache) Document Root hierarchy. That step, alone, is important to force a curious user, to work their way through an inhouse PHP webpage URL of some sort, in order to extract that …

  • image data in the form of a web server file … to a …
  • public domain webpage image in an HTML img tag where its src attribute is populated via that web server file’s equivalent base64 data URI …
    <?php

    echo "<html><body><img title='" . $thename . '' . "' src='data:image/webp;base64," . base64_encode(file_get_contents(DIRECTORY_SEPARATOR . 'tmp' . DIRECTORY_SEPARATOR . $thename . '')) . "'></img>" . $therest . "</body></html>";

    ?>

Am sure you are not surprised that today’s external Javascript web_share_api_test.js Web Share API specialist needed to change


function tctowebp() {
var ourcanvc='';
var canvs=[];
if (window.top) {
canvs=top.document.getElementsByTagName('canvas');
}
if (eval('' + canvs.length) == 0 && window.parent) {
canvs=parent.document.getElementsByTagName('canvas');
}
if (eval('' + canvs.length) == 0) {
canvs=document.getElementsByTagName('canvas');
}
if (eval('' + canvs.length) == 0 && window.parent) {
canvs=parent.document.getElementsByTagName('canvas');
if (eval('' + canvs.length) == 0 && window.top) {
canvs=top.document.getElementsByTagName('canvas');
}
}
if (eval('' + canvs.length) > 0) {
ourcanvc=canvs[0].toDataURL('image/webp');
if (lastcanvc != ' ') {
if (lastcanvc != ourcanvc) {
lastcanvc=ourcanvc;
canvc=ourcanvc;
czhr = new XMLHttpRequest();
czform = new FormData();
czform.append('webpit', canvc);
if (newidea.indexOf('canvas.webp') == -1) { // eg. MAMP ... http://localhost:8888/signature_signature.php?mycanvasimage=0000__1
czform.append('websecurepit', '' + myipadwsi);
}

czhr.onreadystatechange=cstateChanged;
czhr.open('post', './signature_signature.php', true);
czhr.send(czform);
} else {
if (document.getElementById('shareurl')) {
document.getElementById('shareurl').style.backgroundColor='#f9f9f9';
}
}
}
lastcanvc=ourcanvc;
}
return ourcanvc;
}

… as well, regarding its incorporation of Web Share API logic into our inhouse User of Signature canvas based web application, best tried, these days, in the Safari and Google Chrome web browser(s) using https: (secure) protocol?!


Previous relevant Canvas via Imge Web Share API Tutorial is shown below.

Canvas via Image Web Share API Tutorial

Canvas via Imge Web Share API Tutorial

We’re on the lookout for ways to improve the sharing and collaboration functionality of yesterday’s Images to Canvas No Clicking Form Signature Tutorial‘s “User of Signature” canvas using web application. We’re calling on ..

  • Safari and Google Chrome web browser(s) … for the moment, supporting the …
  • Web Share API … in order to …
  • Fill out email (or other communication idea) attachment links or documents … that …
  • Prepare the message before you, the user, flesh out the message as you send it off to the recipient

… a more guaranteed way, these days, because there are more and more ways restrictions may stop you doing similar functionality with a mail server arrangement on your public domain website, where we use the Exim mail server, at the RJM Programming domain.

As far as data goes for this, we also call on our changed PHP helper signature_signature.php to create a webp image file for sharing …

<?php

if (isset($_POST['webpit'])) {
file_put_contents($_SERVER['DOCUMENT_ROOT'] . DIRECTORY_SEPARATOR . 'canvas.webp', base64_decode(explode(";base64,", str_replace(' ','+',urldecode($_POST['webpit'])))[1]));
exit;
}

?>

… as applicable. The modus operandi for this back at today’s changed web_share_api_test.js external Javascript Web Share API specialist, uses Ajax methodologies …


var canvc=' ', lastcanvc=' ', czhr=null, czform=null;

function cstateChanged() {
if (czhr.readyState == 4) {
if (czhr.status == 200) {
if (1 == 2) { alert('Did it'); }
if (document.getElementById('shareurl')) {
document.getElementById('shareurl').style.backgroundColor='yellow';
}
}
}
}

function tctowebp() {
var ourcanvc='';
var canvs=[];
if (window.top) {
canvs=top.document.getElementsByTagName('canvas');
}
if (eval('' + canvs.length) == 0 && window.parent) {
canvs=parent.document.getElementsByTagName('canvas');
}
if (eval('' + canvs.length) == 0) {
canvs=document.getElementsByTagName('canvas');
}
if (eval('' + canvs.length) == 0 && window.parent) {
canvs=parent.document.getElementsByTagName('canvas');
if (eval('' + canvs.length) == 0 && window.top) {
canvs=top.document.getElementsByTagName('canvas');
}
}
if (eval('' + canvs.length) > 0) {
ourcanvc=canvs[0].toDataURL('image/webp');
if (lastcanvc != ' ') {
if (lastcanvc != ourcanvc) {
lastcanvc=ourcanvc;
canvc=ourcanvc;
czhr = new XMLHttpRequest();
czform = new FormData();
czform.append('webpit', canvc);
czhr.onreadystatechange=cstateChanged;
czhr.open('post', './signature_signature.php', true);
czhr.send(czform);
} else {
if (document.getElementById('shareurl')) {
document.getElementById('shareurl').style.backgroundColor='#f9f9f9';
}
}
}
lastcanvc=ourcanvc;
}
return ourcanvc;
}

… and set in motion via a couple of different parental calls such as …


<script type='text/javascript' src='/web_share_api_test.js?canvasshare=as_necessary9876' defer></script>

… in …

… for cuter Safari and Google Chrome web browser sharing and collaboration work.


Previous relevant Images to Canvas No Clicking Form Signature Tutorial is shown below.

Images to Canvas No Clicking Form Signature Tutorial

Images to Canvas No Clicking Form Signature Tutorial

Surprisingly, it’s been more than a year since we changed anything to do with our …

  • canvas based …
  • images and annotation … accepting …
  • scribble (ie. can handle signatures) … perhaps …
  • form filling helping web application

… (when we presented Canvas Graphics Editing in Zoomed Webpage Tutorial) and we found that in order to add six more such Annotation option helpers into the mix …

Image Input Mode Image Sizing Modus Operandi
URL Actual (canvas resized to image)
Contain (canvas)
Cover (canvas)
Browsing Actual (canvas resized to image)
Contain (canvas)
Cover (canvas)

… we only needed to change the external Javascript signature_signature.js code used by our signature use in canvas supervisory web application so that when you can not ask so much of the user regarding image scaling, and avoid any canvas clicking that way, offering these six new annotation functionality options.


Previous relevant Canvas Graphics Editing in Zoomed Webpage Tutorial is shown below.

Canvas Graphics Editing in Zoomed Webpage Tutorial

Canvas Graphics Editing in Zoomed Webpage Tutorial

Software integration can be useful for a number of reasons …

  • code reuse
  • modularisation of functionality … and in our case …
  • if you like coding via “intervention points” you will enjoy coding for software integration improvements

As you might imagine it is easier in terms of the fact you can change “both ends” of the software integration, if it is “inhouse”, and luckily, today, our software integration is “inhouse”.

When we presented the recent Keyboard Based Cursor Canvas Content Copy Tutorial it focussed our attention on an improvement we could make to that user_of_signature_signature.htm canvas image editing web application. We wanted to offer the software integration with this web application to be able to successfully handle a webpage that has been zoomed to zoom factor different to 1.0 (or 100%).

We noticed before today’s very simple changes to external Javascript signature_signature.js code, graphic positioning on the canvas was wrong when the webpage had a zoom factor that is not 1.

Applying the canvas co-ordinate references through “the lens of” Javascript function zmb below …


var zzfac=location.search.split('zoom=')[1] ? decodeURIComponent(location.search.split('zoom=')[1].split('&')[0]) : "";
if (('' + location.hash).indexOf('zoom=') != -1) { zzfac=decodeURIComponent(('' + location.hash).split('zoom=')[1].split(';')[0]); }

function zmb(inco) {
if (zzfac != '') {
if (zzfac.indexOf('%') != -1) {
return eval(eval(eval('' + inco) / eval('' + zzfac.replace('%', ''))) * 100.0);
} else {
return eval(eval('' + inco) / eval('' + zzfac));
}
}
return inco;
}

used in the following example code below …


topelem.addEventListener('mousedown', function(event) {
if (topin) {
topin.value='- -' + isScribble + ',' + lastx + ',' + lasty + ',' + x + ',' + y;
}
if (isScribble == 1) {
threebackpmore=twobackpmore; twobackpmore=lastpmore; lastpmore=pmore; pmore=' pxam1 ';
isScribble=2;
if (event.pageX || event.pageY) {
ppx=zmb(event.pageX) - elemLeft;
ppy=zmb(event.pageY) - elemTop;
} else {
ppx=zmb(event.clientX) - elemLeft;
ppy=zmb(event.clientY) - elemTop;
}
if (pdgebi(topdcmcheck('dcm'))) {
if (parent.document.getElementById(topdcmcheck('dcm')).value.indexOf('text') == 0) {
//parent.document.title='here3 ' + tx + ',' + ty;
if (1 == 2 && tlx < 0 && tly < 0) {
tlx=ppx;
tly=ppy;
}
if (tx >= 0 && ty >= 0) {
prevtx=tx;
prevty=ty;
trotis=eval(((Math.atan2((ppy - prevty), (ppx - prevtx)) * 180.0 / Math.PI) + 360) % 360);
if (pdgebi('trotation')) {
if (parent.document.getElementById(topdcmcheck('dcm')).value.indexOf('textseq') == 0) {
jsrectbits[0]=prevtx;
jsrectbits[1]=prevty;
jsrectbits[2]=ppx;
jsrectbits[3]=ppy;
if (Math.abs(prevty - ppy) > Math.abs(prevtx - ppx)) {
trotis=eval(((Math.atan2((prevtx - ppx), (ppy - prevty)) * 180.0 / Math.PI) + 360) % 360);
}
}
parent.document.getElementById('trotation').value=Math.floor(trotis);
ppx=prevtx;
ppy=prevty;
prevtx=-1;
prevty=-1;
exceptwhen=endtrue(''); //true;
if (parent.document.getElementById(topdcmcheck('dcm')).value.indexOf('textseq') == -1) parent.document.getElementById(topdcmcheck('dcm')).value = 'Text';
}
//alert(trotis);
}
tx=ppx;
ty=ppy;
} else {
tx=ppx;
ty=ppy;
prevtx=-1;
prevty=-1;
}
} else {
tx=ppx;
ty=ppy;
prevtx=-1;
prevty=-1;
}
lastx=0; // new to scribble
lasty=0;
x=0;
y=0;
}
});

… we now have reasonable graphic positioning for the canvas when its webpage window has a non 1.0 zoom factor applied.


Previous relevant Keyboard Based Cursor Canvas Content Copy Tutorial is shown below.

Keyboard Based Cursor Canvas Content Copy Tutorial

Keyboard Based Cursor Canvas Content Copy Tutorial

You may have noticed with yesterday’s Keyboard Based Cursor Share Content Copy Tutorial, crucial to the sharing code, was the use of the incredible HTML5 introduced canvas element, helped by that middleperson link to those public email and SMS sharing conduits, overseeing the great random Lorem Picsum background images and user created emoji and/or text initial annotations.

And this got us wondering whether there was a private (ie. inhouse) web application of the past that could further value add as another optional middleperson tool for (user) personalization (of the content) purposes. And yes, do you remember the canvas work involved in the featured web application of Emoji Borders and Backgrounds Canvas Annotation Tutorial?

It uses an interesting approach with the transference of data across from a canvas in one application to the canvas in that user_of_signature_signature.htm web application. Once our changed body_mouse_deepdive.html‘s “parent” web application has organized its canvas contents, it’s just a matter of …


var awo=null;
awo=window.open('./user_of_signature_signature.htm','_blank','top=100,left=100,width=800,height=800');

for the “child” canvas annotator to effectively “suck up” the canvas data into its canvas via …


var cancont='';
var elemode=location.search.split('elemode=')[1] ? (location.search.split('elemode=')[1].split('&')[0]) : "canvas";

if (('' + window.opener).replace('null','') != '') {
var cans=window.opener.document.getElementsByTagName(elemode);
if (cans.length > 0) {
if (elemode == 'img') {
cancont=cans[0].src;
} else {
cancont=cans[0].toDataURL('image/png');
}
if (cancontw < 0 && canconth < 0) { cancontw=cans[0].width; canconth=cans[0].height; } } }

... possible because both "parent" and "child" exist on the same RJM Programming domain (web server).

Once there, another woooooorrrrrlllddd of image manipulations, via canvas, can await the user, perhaps ready for ongoing sharing possibilities with that "child".


Previous relevant Keyboard Based Cursor Share Content Copy Tutorial is shown below.

Keyboard Based Cursor Share Content Copy Tutorial

Keyboard Based Cursor Share Content Copy Tutorial

Yesterday's Keyboard Based Cursor Personalized Content Copy Tutorial has probably reached a point where some sharing mechanism is apt, for accountability and usefulness purposes, at the very least, regarding our recent web application allowing for foreground content on top of a random Lorem Picsum background image.

We've been helped out greatly by javascript - Can I take a screenshot from the clipboard? - Stack Overflow and html - How to render a blob on a canvas element? - Stack Overflow in the following new relevant Javascript code ...


function renderNoImage(canvas, blob) { // thanks to https://stackoverflow.com/questions/38004917/how-to-render-a-blob-on-a-canvas-element
const ctx = canvas.getContext('2d');
const img = new Image();
img.onload = (event) => {
URL.revokeObjectURL(event.target.src) // This is important. If you are not using the blob, you should release it if you don't want to reuse it. It's good for memory.
ctx.drawImage(event.target, 0, 0)
img.style.display='none';
img.style.zIndex='-123';
};
img.src = URL.createObjectURL(blob);
}


function renderImage(canvas, blob) { // thanks to https://stackoverflow.com/questions/38004917/how-to-render-a-blob-on-a-canvas-element
const ctx = canvas.getContext('2d');
const img = new Image();
img.onload = (event) => {
URL.revokeObjectURL(event.target.src) // This is important. If you are not using the blob, you should release it if you don't want to reuse it. It's good for memory.
ctx.drawImage(event.target, 0, 0)
};
img.src = URL.createObjectURL(blob);
}


addEventListener("paste", ev => { // thanks to https://stackoverflow.com/questions/55559432/can-i-take-a-screenshot-from-the-clipboard
for(const item of ev.clipboardData.items) { /// Clipboard may contain multiple elements of different type -- text, image, etc
if(item.type.startsWith("image/")) { /// We are only interested in clipboard data that is an image
if (emailee == '') {
emailee=prompt('Your clipboard has a useful image you could share the image with. Optionally, please enter an email address or SMS number to share with.');
if (emailee == null) { emailee=''; }
}
if (emailee.indexOf('@') != -1) {
document.getElementById('mydiv').style.overflow='scroll';
document.getElementById('mycanvas').innerHTML='<br><canvas style="position:absolute;z-index:98;top:0px;left:0px;" id=thecanvas width=' + screen.width + ' height=' + screen.height + '></canvas>';
elem=document.getElementById('thecanvas');
context=elem.getContext('2d');
renderImage(elem, item.getAsFile()); //context.drawImage(item.getAsFile(), 0, 0);
document.getElementById('aemail').href=document.getElementById('aemail').href.replace(':?', ':' + emailee + '?');
document.getElementById('aemail').click();
document.getElementById('mycanvas').innerHTML='';
} else if (emailee != '' && emailee.replace(/0/g,'').replace(/1/g,'').replace(/2/g,'').replace(/3/g,'').replace(/4/g,'').replace(/5/g,'').replace(/6/g,'').replace(/7/g,'').replace(/8/g,'').replace(/9/g,'') == '') {
document.getElementById('mydiv').style.overflow='scroll';
document.getElementById('mycanvas').innerHTML='<br><canvas style="position:absolute;z-index:98;top:0px;left:0px;" id=thecanvas width=' + screen.width + ' height=' + screen.height + '></canvas>';
elem=document.getElementById('thecanvas');
context=elem.getContext('2d');
renderImage(elem, item.getAsFile()); //context.drawImage(item.getAsFile(), 0, 0);
document.getElementById('asms').href=document.getElementById('asms').href.replace(':&', ':' + emailee + '&');
document.getElementById('asms').click();
document.getElementById('mycanvas').innerHTML='';
} else {
//document.getElementById('mydiv').style.overflow='scroll';
document.getElementById('mycanvas').innerHTML='<br><canvas style="display:none;position:absolute;z-index:-98;top:0px;left:0px;" id=thecanvas width=' + screen.width + ' height=' + screen.height + '></canvas>';
elem=document.getElementById('thecanvas');
context=elem.getContext('2d');
renderNoImage(elem, item.getAsFile()); //context.drawImage(item.getAsFile(), 0, 0);
document.getElementById('mycanvas').innerHTML='';
}
}
}
});

... which is explained to the user in the following way ...

Share with email or SMS happens via screenshots (macOS control-command-shift-3 or Windows Prnt-Scrn) followed by File menu Paste option causing chance to share after which File menu Undo can remove pasted part as required.

... in the changed "proof of concept" body_mouse_deepdive.html live run.


Previous relevant Keyboard Based Cursor Personalized Content Copy Tutorial is shown below.

Keyboard Based Cursor Personalized Content Copy Tutorial

Keyboard Based Cursor Personalized Content Copy Tutorial

On top of yesterday's Keyboard Based Cursor Content Copy Tutorial we wanted to offer the user the chance for them to tailor their foreground content on top of the Lorem Picsum background image.

The user can enter this via the keyboard because there is an HTML div contenteditable=true pallette to work with ...


<div id=mydiv onfocus='setTimeout(alte, 1000);' ondblclick="this.innerHTML='';" onclick='stamp(event);' title='Click and type and see the cursor change as you use Alt or Shift or Control that can be reset via Caps Lock with a click copying cursor into content ... RJM Programming ... May, 2022 ... thanks to https://picsum.photos/ Lorem Picsum You can change emojis if you know the \002602 form of UTF-16 (hex) entry (our example is umbrella and if you express it as \\002602 that leaves cursor just as your emoji). Double click existant foreground emoji element to clear all the foreground emoji elements.' spellcheck='false' contenteditable=true style='width:100vw;height:100%;color:transparent;text-color:transparent;' onkeypress=kpcursorlook(event); onkeydown=cursorlook(event); onmousemove=xycursorlook(event); ontouchmove=xycursorlook(event);></div>

It's "title" attribute now talks about two new pieces of functionality, those being ...

  • You can change emojis if you know the \002602 form of UTF-16 (hex) entry (our example is umbrella and if you express it as \\002602 that leaves cursor just as your emoji).
  • Double click existant foreground emoji element to clear all the foreground emoji elements.

The choice of keyboard input methodology also suits CSS "content" property definitions as one backslash followed by a hexidecimal value left padded with zeroes to a length of six. See us doing this below for an umbrella emoji (which could also be expressed in an HTML hexadecimal entity way &#x2602; ☂ the information for which you can find at Unicode Character 'UMBRELLA' (U+2602) we normally get to by entering "U+2602" at a web browser address bar, the knowledge for which we arrive at via entering "umbrella emojipedia" and moving down the top link's webpage to find the "U+2602") ...


<style> #myumbrella::after { content: '\002602'; } </style>

... that feeds into some new "onkeypress" keyboard event logic ...


function kpcursorlook(evt) {
var atofa=['a','b','c','d','e','f'];
var rgbit='';
if (evt.keyCode == 92) {
if (newu.length == 1) { gro=true; } else { gro=false; }
newu=("\\").substring(0,1);
} else if (evt.keyCode >= 48 && evt.keyCode <= 57) {
newu+=('' + eval(-48 + evt.keyCode));
} else if (evt.keyCode >= 65 && evt.keyCode <= 70) {
newu+=('' + atofa[eval(-65 + evt.keyCode)]);
} else if (evt.keyCode >= 97 && evt.keyCode <= 102) {
newu+=('' + atofa[eval(-97 + evt.keyCode)]);
}
if (newu.length == 7) {
if (lastcursor.indexOf(("\\\\").substring(0,2)) != -1) {
rgbit=lastcursor.split(("\\\\").substring(0,2))[1].substring(6);
lastcursor=lastcursor.split(("\\\\").substring(0,2))[0] + ("\\").substring(0,1) + newu + rgbit;
document.head.innerHTML+='<style> html { cursor: ' + lastcursor + '; } </style>';
} else if (lastcursor.indexOf(("\\").substring(0,1)) != -1) {
rgbit=lastcursor.split(("\\").substring(0,1))[1].substring(6);
lastcursor=lastcursor.split(("\\").substring(0,1))[0] + newu + rgbit;
if (gro) {
lastcursor=lastcursor.replace('>Shift/Alt/Ctrl', '>').replace('>Shift', '>').replace('>Alt', '>').replace('>Ctrl', '>').replace(" width='126'", " width='20'").replace(" width='66'", " width='20'").replace(" height='48'", " height='20'").replace('0 0 100 100', '0 0 20 20');
}
document.head.innerHTML+='<style> html { cursor: ' + lastcursor + '; } </style>';
}
}
// console.log(evt.keyCode);
}

... in the changed "proof of concept" body_mouse_deepdive.html live run.

Stop Press

Two more "title" attribute pieces of functionality are now ...

  • With complex emoji entries do not zero leftpad until your last simple entity eg. \\1F6A3\200D\2640\00FE0F could define a Woman Rowing complex emoji.
  • Optionally make emojis bigger after \ with + two time multipliers.

The choice of keyboard input methodology also suits CSS "content" property definitions as one backslash followed by "first off" sets of HTML entities they should not left zero pad in their entry, followed by a last HTML entity hexidecimal value left padded with zeroes to a length of six to finish up with. See us doing this below for a woman rowing emoji (which could also be expressed in an HTML hexadecimal entity way &#x1f6a3;&#x0200d;&#x02640;&#x0fe0f; the information for which you can find at 🚣‍♀️ Woman Rowing Boat Emoji we normally get to by entering "woman rowing emoji" at the web browser address bar) ...


<style> #myrowing::after { content: '\01f6a3\00200d\002640\00fe0f'; } </style>

... in the changed "proof of concept" body_mouse_deepdive.html live run.


Previous relevant Keyboard Based Cursor Content Copy Tutorial is shown below.

Keyboard Based Cursor Content Copy Tutorial

Keyboard Based Cursor Content Copy Tutorial

The "onkeydown" keyboard event can involve in its logic three mouse event (event object) property usages that caught our interest recently ...

... and we wanted to have "keyboard" meets "mouse" events, along with the brilliance of Lorem Picsum regarding background image randomosity and quality, working with HTML ...


<div id=mydiv onfocus='setTimeout(alte, 1000);' onclick='stamp(this);' title='Click and type and see the cursor change as you use Alt or Shift or Control that can be reset via Caps Lock with a click copying cursor into content ... RJM Programming ... May, 2022 ... thanks to https://picsum.photos/ Lorem Picsum' spellcheck='false' contenteditable=true style='width:100vw;height:100%;color:transparent;text-color:transparent;' data-onkeypress=xycursorlook(event); onkeydown=cursorlook(event); onmousemove=xycursorlook(event); ontouchmove=xycursorlook(event);></div>

... in a way we hadn't tried before that called on some inhouse cursor SVG creations (and so is, alas, just a non-mobile fully featured experience), in the sense that ...

  1. keyboard helps creating the "what" regarding content ...

    <script type='text/javascript'>
    var lastkeymodifier=''
    var lastcursor="Url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='126' height='48' viewport='0 0 100 100' style='border-radius:15px;background-color:rgba(0,255,0,0.3);fill:black;font-family:Verdana;font-size:16px;'><text y='80%'>Shift/Alt/Ctrl\\002753</text></svg>\") 16 0, crosshair";
    var pos3=-1, pos4=-1;
    var subdiv=1;
    var lastpos3=-2, lastpos4=-1;
    var allowable=false;

    function cursorlook(evt) {
    if (evt.altKey) {
    if (lastkeymodifier != 'alt') {
    lastcursor="Url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='66' height='48' viewport='0 0 100 100' style='border-radius:15px;background-color:rgba(0,0,255,0.3);fill:black;font-family:Verdana;font-size:17px;'><text y='80%'>Alt\\01f3d5</text></svg>\") 16 0, progress";
    document.head.innerHTML+='<style> html { cursor: ' + lastcursor + '; } </style>';
    lastkeymodifier='alt';
    }
    } else if (evt.ctrlKey) {
    if (lastkeymodifier != 'ctrl') {
    lastcursor="Url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='66' height='48' viewport='0 0 100 100' style='border-radius:15px;background-color:rgba(0,255,0,0.3);fill:black;font-family:Verdana;font-size:17px;'><text y='80%'>Ctrl\\01f333</text></svg>\") 16 0, pointer";
    document.head.innerHTML+='<style> html { cursor: ' + lastcursor + '; } </style>';
    lastkeymodifier='ctrl';
    }
    } else if (evt.shiftKey) {
    if (lastkeymodifier != 'shift') {
    lastcursor="Url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='66' height='48' viewport='0 0 100 100' style='border-radius:15px;background-color:rgba(255,0,0,0.3);fill:black;font-family:Verdana;font-size:17px;'><text y='80%'>Shift\\01f389</text></svg>\") 16 0, grab";
    document.head.innerHTML+='<style> html { cursor: ' + lastcursor + '; } </style>';
    lastkeymodifier='shift';
    }
    } else {
    if (lastkeymodifier != '') {
    lastcursor="Url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='126' height='48' viewport='0 0 100 100' style='border-radius:15px;background-color:rgba(0,255,0,0.3);fill:black;font-family:Verdana;font-size:16px;'><text y='80%'>Shift/Alt/Ctrl\\002753</text></svg>\") 16 0, crosshair";
    document.head.innerHTML+='<style> html { cursor: ' + lastcursor + '; } </style>';
    lastkeymodifier='';
    }
    }
    }
    </script>
  2. mouse "onmousemove" or "ontouchmove" helps with the "where" regarding content above ...

    <script type='text/javascript'>
    var pos3=-1, pos4=-1;
    var subdiv=1;
    var lastpos3=-2, lastpos4=-1;
    var allowable=false;

    function xycursorlook(e) {
    e = e || window.event;
    e.preventDefault();

    if (e.touches) {
    if (e.touches[0].pageX) {
    pos3 = e.touches[0].pageX;
    pos4 = e.touches[0].pageY;
    } else {
    pos3 = e.touches[0].clientX;
    pos4 = e.touches[0].clientY;
    }
    //console.log('pos3=' + pos3 + ',pos4=' + pos4);
    } else if (e.clientX || e.clientY) {
    pos3 = e.clientX;
    pos4 = e.clientY;
    } else {
    pos3 = e.pageX;
    pos4 = e.pageY;
    }
    }
    </script>
  3. preparations for "onclick" way a cursor can be plonked into (real lasting) content ...

    <script type='text/javascript'>
    var lastcursor="Url(\"data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='126' height='48' viewport='0 0 100 100' style='border-radius:15px;background-color:rgba(0,255,0,0.3);fill:black;font-family:Verdana;font-size:16px;'><text y='80%'>Shift/Alt/Ctrl\\002753</text></svg>\") 16 0, crosshair";
    var pos3=-1, pos4=-1;
    var subdiv=1;
    var lastpos3=-2, lastpos4=-1;
    var allowable=false;

    function stamp(divo) {
    if (('' + pos3).indexOf('-') == -1) {
    if (allowable) {
    //if (allowed) {
    //allowed=false;
    //setTimeout(reseta, 2000);
    divo.innerHTML+='<div id=div' + subdiv + ' style="position:absolute;top:' + pos4 + 'px;left:' + pos3 + 'px;width:126px;height:48px;background-color:transparent;"></div><style> #div' + subdiv + ' { background:' + lastcursor.split(') ')[0] + ') no-repeat; } </style>';
    subdiv++;
    //console.log('lastpos4=' + lastpos4 + ' and pos4=' + pos4);
    //console.log('lastpos3=' + lastpos3 + ' and pos3=' + pos3);
    lastpos3=pos3;
    lastpos4=pos4;
    //}
    }
    }
    }
    </script>

... with the "proof of concept" body_mouse_deepdive.html live run.

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.

This entry was posted in Animation, eLearning, Event-Driven Programming, Tutorials and tagged , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *