/* jseyes3_5T.js
The classic Xeyes in JavaScript
Written by Pintér Gábor
Feuerwehrgasse 1/2/9
Purbach am Neusiedlersee
A-7083, Austria
Tel: +43 681 20821067, +36 20 4331532
Email: [email protected]
Web: http://pintergabor.eu/en/
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
Revisions:
V1.0 2001-10-14 Original release.
V1.1 2001-12-08 NS6.1
V1.2 2001-12-17 More parameters
V1.3 2002-08-14 Adjustable speed
V1.31 2002-08-26 Improved adjustable speed
V1.4 2010-11-26 IE7, IE8, absolute position
V2.0 2014-03-13 Object oriented, IE9+
Based on V1.0: Portions added/modified by Tori T, Gmail is tori(dot)t(dot)uk
v2.0T 05 May 2019: Edited to allow easy replacement of background and eye images.
v2.1T 08 May 2019: Added JS controlled CSS to allow cursor to be changed to an appropriate bitmap for the eyes to follow.
v3.0T 12 May 2019: Edited to allow user selection of up 1-4 eyes (1-2 people/animals).
v3.1T 13 May 2019: Now supports 1-8 eyes (Up to 4 people/animals or 1 Eldritch Horror).
v3.2T 03 Jun 2019: Calculates the pupil movement constraint parameters from the eye width, height, and pupil size values.
v3.3T 15 Jun 2019: Auto image size aquisition. Code optimisation.
v3.4T 21 Jun 2019: Checks/reports on missing images. Transparent eye support added.
v3.5T 27 Jun 2019: Moved settings.js to separate file(s). Transparent eye background color support added.
Usage:
1. Include these files in the <head> tag of your web page.
Insert the following:
<script src="settings.js"></script>
<script src="jseyes3_5T.js"></script>
2. Insert the script call in the <body> tag of your page where you want to see the image.
Insert the following:
<script>
jseyes();
</script>
Or call jseyes(x, y) to show the image at absolute position:
<script>
jseyes(100,100);
</script>
3. Edit the parameters in settings.js or replace with one of the pre-prepared alternatives.
*/
// This is where the setting were before moving to a separate file.
// Don't change the stuff below this point (unless you really want to).
// Internal variables.
// bkgImg_x and bkgImg_y are the width and height in pixels of jsbkgimg.
// pupil_x and pupil_y are the width and height in pixels of jseyeimg.
// cursor_id_x and cursor_id_y are the width and height in pixels of cursorimg.
var bkgImg_x, bkgImg_y, pupil_x, pupil_y, cursor_id_x, cursor_id_y;
// center_x[0] and center_y[0] are the center of the leftmost eye in background image jsbkgimg measured from (0,0).
// They're the same as the start_?[0] values. The center_?[1..7] variables are offsets calculated from those start values.
// The circle_x&y[0..7] are perimeter values of each eye, so that the pupil stays within the border of the eye when moving.
var center_x= [], center_y= [];
var circle_x= [], circle_y= [], loop;
var jseyeso= null, jseye0= null, jseye1= null, jseye2= null, jseye3= null, jseye4= null, jseye5= null, jseye6= null, jseye7= null;
var sheet= window.document.styleSheets[0]; // JS link to the external stylesheet.
var x, y, a=false; // The optional positioning parameters passed from jseyes() on the web page to main().
var tot_center_x= [], tot_center_y= []; // Eye behaviour calculation arrays.
var eye_z= 6; // Sets default pupil z-index.
function javascript_abort() { // Might need this later.
throw new Error('This is not an error. This is just to abort javascript');
}
// Sets the page title, then preloads the background image. Leaves an error message if loading fails.
function jseyes() {
if (arguments.length==2) {
x= arguments[0];
y= arguments[1];
a= true;
}
// Calculates the eye offsets used in the calculations.
center_x[0]= start_x[0], center_y[0]= start_y[0];
for (loop=1; loop<8; loop++) {
center_x[loop]= start_x[loop]-start_x[loop-1];
center_y[loop]= start_y[loop-1]-start_y[loop];
}
document.getElementById("eyes_main").innerHTML= ""; // If this runs, the settings were found; remove that error message.
if (js_page_title != "") {
document.title= js_page_title;
// document.getElementById("js_title").innerHTML= js_page_title; Not used by TonyMac86.
}
document.getElementById("img_init").innerHTML= '<img id="the_background" alt="'
+jsbkgimg
+' not found. Check file name and path." src="'
+jsbkgimg
+'" width=0 height=0 onload="init_2()">';
}
// Gets the background image size in pixels, checks for out-of-range co-ordinates, then preloads the eye image.
function init_2() {
var background_id= document.getElementById('the_background');
bkgImg_x= background_id.naturalWidth;
bkgImg_y= background_id.naturalHeight;
for (loop=0; loop<(jseyetotal); loop++) { // If an eye is outside the image border you may not see it, or know which value is wrong.
// You can comment out/delete this routine if that's what you require.
if (start_x[loop]< 0+(eye_w[loop]/2) || start_x[loop]> bkgImg_x-(eye_w[loop]/2)) {
document.getElementById("error").innerHTML= "Co-ordinate start_x["
+loop
+"] will put the eye outside the boundries of "
+jsbkgimg;
}
if (start_y[loop]< 0+(eye_h[loop]/2) || start_y[loop]> bkgImg_y-(eye_h[loop]/2)) {
document.getElementById("error").innerHTML= "Co-ordinate start_y["
+loop
+"] will put the eye outside the boundries of "
+jsbkgimg;
}
}
document.getElementById("img_init").innerHTML= '<img id="the_eyeball" alt="'
+jseyeimg
+' not found. Check file name and path." src="'
+jseyeimg
+'" width=0 height=0 onload="init_3()">';
}
// Gets the eye image size in pixels, then (optionally) loads the cursor image.
function init_3() {
var eyeball_id= document.getElementById('the_eyeball');
pupil_x= eyeball_id.naturalWidth;
pupil_y= eyeball_id.naturalHeight;
if (cursorimg != "") { //Only preload the cursor if that option's been set.
document.getElementById("img_init").innerHTML= '<img id="the_cursor" alt="'
+cursorimg
+' not found. Check file name and path." src="'
+cursorimg
+'" width=0 height=0 onload="init_4()">';
} else {
init_4();
}
// main();
}
// Gets the size of the cursor image, sets the cursor, then calculates the eyeball behaviour parameters.
function init_4() {
if (cursorimg != "") { // Get the cursor image size if it's been loaded.
var cursor_id= document.getElementById('the_cursor');
cursor_id_x= cursor_id.naturalWidth;
cursor_id_y= cursor_id.naturalHeight;
if (cursor_x == -1) { //Centers the cursor focus point if not explicitly set.
cursor_x= (cursor_id_x/2);
cursor_y= (cursor_id_y/2);
} // NOTE: The additional "../" in the cursor url is necessary because the .js file looks at things from the
// location of the .html file it's running from, but the .css file looks at things from it's location in the
// "/files" directory it's located in. If images/style sheets/scripts are located in the same directory, you
// can get rid of it. This doesn't apply to TonyMac86.
// sheet.insertRule('body {cursor: url(../'+cursorimg+') '+cursor_x+' '+cursor_y+', crosshair;}', sheet.cssRules.length);
sheet.insertRule('body {cursor: url('+cursorimg+') '+cursor_x+' '+cursor_y+', crosshair;}', sheet.cssRules.length);
} else {
sheet.insertRule('body {cursor: crosshair;}', sheet.cssRules.length);
}
document.getElementById("img_init").innerHTML= ""; // Remove any residual preloaded image data.
if (eyes_to_back != "") { // Check if a transparent image is being used.
if (eyes_to_back == "y" || eyes_to_back == "Y") {
eye_z= -1; // Sets the z-index to place the pupil behind the background.
if (bg_color != "") { // If the bg color is set.
sheet.insertRule('td {background-color: '+bg_color+';}', sheet.cssRules.length);
}
for (loop=0; loop<8; loop++) {
eye_w[loop]*= 1.15; // Increases the eye size by 15% so the pupil moves behind the edges.
eye_h[loop]*= 1.15;
}
}
}
for (loop=0; loop<8; loop++) { // Calculates the eye perimeter values.
circle_x[loop]= ((eye_w[loop]/2)-(pupil_x/2))*((eye_w[loop]/2)-(pupil_x/2));
circle_y[loop]= ((eye_h[loop]/2)-(pupil_y/2))*((eye_h[loop]/2)-(pupil_y/2));
}
var calc_loop_a, calc_loop_b;
for (calc_loop_a = 0; calc_loop_a < 8; calc_loop_a++) { // Zeros the offset chains.
tot_center_x[calc_loop_a]= 0;
tot_center_y[calc_loop_a]= 0;
}
for (calc_loop_a = 0; calc_loop_a < 8; calc_loop_a++) { // Calculates the offset chains for all eyes.
for (calc_loop_b = 0; calc_loop_b < calc_loop_a+1; calc_loop_b++) {
tot_center_x[calc_loop_a]+= center_x[calc_loop_b];
calc_loop_check_b= calc_loop_b;
if (calc_loop_b == 0) {
tot_center_y[calc_loop_a]+= center_y[calc_loop_b];
} else {
tot_center_y[calc_loop_a]-= center_y[calc_loop_b];
}
}
}
main();
}
// Find object by name or id
function jseyesobj(id) {
var i, x;
x= document[id];
if (!x && document.all) x= document.all[id];
for (i=0; !x && i<document.forms.length; i++) x= document.forms[i][id];
if (!x && document.getElementById) x= document.getElementById(id);
return(x);
}
// Move eyes
function jseyesmove(x, y) { // x & y are variable cursor offsets from top left of browser window.
var dx, dy, ex, ey; // ex & ey are fixed offsets of top left corner of jsbkgimg from top left of browser window.
var r= []; // dx & dy are variable cursor offsets from the center of the eye being processed.
var jseye_l= [], jseye_t= [], jseye_loop;
if (jseyeso && jseye0 && jseye1 && jseye2 && jseye3 && jseye4 && jseye5 && jseye6 && jseye7 && jseyeso.style) {
ex= jseyeso.offsetLeft+center_x[0];
ey= jseyeso.offsetTop+center_y[0];
// ###### EYE #0-#7 CODE #######
for (jseye_loop=0; jseye_loop<8; jseye_loop++) {
if (jseye_loop == 0) {
dx= x-ex;
dy= y-ey;
} else {
dx-= center_x[jseye_loop];
dy+= center_y[jseye_loop];
}
r[jseye_loop]= (dx*dx/circle_x[jseye_loop]+dy*dy/circle_y[jseye_loop]< 1) ? 1 : Math.sqrt(circle_x[jseye_loop]*circle_y[jseye_loop]/(dx*dx*circle_y[jseye_loop]+dy*dy*circle_x[jseye_loop]));
jseye_l[jseye_loop]= r[jseye_loop]*dx+((tot_center_x[jseye_loop])-(pupil_x/2))+'px';
jseye_t[jseye_loop]= r[jseye_loop]*dy+((tot_center_y[jseye_loop])-(pupil_y/2))+'px';
}
}
jseye0.style.left= jseye_l[0], jseye0.style.top= jseye_t[0];
jseye1.style.left= jseye_l[1], jseye1.style.top= jseye_t[1];
jseye2.style.left= jseye_l[2], jseye2.style.top= jseye_t[2];
jseye3.style.left= jseye_l[3], jseye3.style.top= jseye_t[3];
jseye4.style.left= jseye_l[4], jseye4.style.top= jseye_t[4];
jseye5.style.left= jseye_l[5], jseye5.style.top= jseye_t[5];
jseye6.style.left= jseye_l[6], jseye6.style.top= jseye_t[6];
jseye7.style.left= jseye_l[7], jseye7.style.top= jseye_t[7];
}
// Mouse move events
function jseyesmousemove(e) {
var mousex= (e)? e.pageX : event.clientX+standardbody.scrollLeft;
var mousey= (e)? e.pageY : event.clientY+standardbody.scrollTop;
jseyesmove(mousex, mousey);
// return(false);
}
// Main code
function main() {
var full_img= "", img_head= "", img_foot= "";
var img= [], html_loop;
for (html_loop = 0; html_loop < 8; html_loop++) {
img[html_loop]= "";
}
img_head= "<div id='jseyeslayer' style='position:"
+(a ? "absolute; left:"
+x
+"; top:"
+y : "relative")
+"; z-index:5; width:"
+bkgImg_x
+"px; height:"
+bkgImg_y
+"px; overflow:hidden'>";
if (jseyetotal <1) jseyetotal= 1; // You can't run with no eyes.
for (html_loop = 0; html_loop < 8; html_loop++) { // Place eye and set position, if selected.
if (jseyetotal >=(html_loop+1)) {
img[html_loop]= "<div id='jseye"
+html_loop
+"' style='position:absolute; left:"
+(start_x[html_loop]-(pupil_x/2))
+"; top:"
+(start_y[html_loop]-(pupil_y/2))
+"; z-index:"
+eye_z
+"; width:"
+pupil_x
+"; height:"
+pupil_y
+"'>"
+"<img src='"
+jseyeimg
+"' alt='The eyeball' width="
+pupil_x
+" height="
+pupil_y
+" onClick=\location.href='"
+jseyelink
+"' title='"
+jseyelinktitle
+"'\></div>";
} else { // Don't place the eye if not selected.
img[html_loop]= "<div id='jseye"
+html_loop
+"' style='position:absolute; left:"
+(start_x[html_loop]-(pupil_x/2))
+"; top:"
+(start_y[html_loop]-(pupil_y/2))
+"; z-index:-1"
+"'></div>";
}
}
if (eyes_to_back != "") { // Check if a transparent image is being used.
if (eyes_to_back == "y" || eyes_to_back == "Y") { // Attach (optional) link code to background because
img_foot= "<img src='" // transparency puts eyeball links behind it.
+jsbkgimg
+"' alt='The background' width="
+bkgImg_x
+" height="
+bkgImg_y
+" onClick=\location.href='"
+jseyelink
+"' title='"
+jseyelinktitle
+"'></div>";
} else {
img_foot= "<img src='"
+jsbkgimg
+"' alt='The background' width="
+bkgImg_x
+" height="
+bkgImg_y
+"></div>";
}
} else {
img_foot= "<img src='"
+jsbkgimg
+"' alt='The background' width="
+bkgImg_x
+" height="
+bkgImg_y
+"></div>";
}
full_img= img_head+img[0]+img[1]+img[2]+img[3]+img[4]+img[5]+img[6]+img[7]+img_foot;
// document.write(full_img);
document.getElementById("eyes_main").innerHTML= full_img;
jseyeso= jseyesobj('jseyeslayer');
jseye0= jseyesobj('jseye0');
jseye1= jseyesobj('jseye1');
jseye2= jseyesobj('jseye2');
jseye3= jseyesobj('jseye3');
jseye4= jseyesobj('jseye4');
jseye5= jseyesobj('jseye5');
jseye6= jseyesobj('jseye6');
jseye7= jseyesobj('jseye7');
jseye0.style.left= (start_x[0]-(pupil_x/2)) + "px", jseye0.style.top= (start_y[0]-(pupil_y/2)) + "px";
jseye1.style.left= (start_x[1]-(pupil_x/2)) + "px", jseye1.style.top= (start_y[1]-(pupil_x/2)) + "px";
jseye2.style.left= (start_x[2]-(pupil_x/2)) + "px", jseye2.style.top= (start_y[2]-(pupil_x/2)) + "px";
jseye3.style.left= (start_x[3]-(pupil_x/2)) + "px", jseye3.style.top= (start_y[3]-(pupil_x/2)) + "px";
jseye4.style.left= (start_x[4]-(pupil_x/2)) + "px", jseye4.style.top= (start_y[4]-(pupil_x/2)) + "px";
jseye5.style.left= (start_x[5]-(pupil_x/2)) + "px", jseye5.style.top= (start_y[5]-(pupil_x/2)) + "px";
jseye6.style.left= (start_x[6]-(pupil_x/2)) + "px", jseye6.style.top= (start_y[6]-(pupil_x/2)) + "px";
jseye7.style.left= (start_x[7]-(pupil_x/2)) + "px", jseye7.style.top= (start_y[7]-(pupil_x/2)) + "px";
document.onmousemove=jseyesmousemove;
}