Thursday, August 28, 2008

Javascript digital counter

I tought of something else I can also do with the digital clock script. Using quite the same code as before, I made a counter, which is a very convinient way to tell the users how much they have been on your site. It starts as the page loads, from "00:00:00" and goes up each second. Of course, you can change the starting value if you need to, just edit it in the code.
Here is the code:
window.onload = function()
{
 //draw the clock when the page loads
 draw_clock('counter');
}

function draw_clock(id)
{
 //create the div that will hold the clock
 var clock = document.createElement('div');

 clock.id = id;
 
 //you can change the style of the clock ie to position it at a specific place on the page
 //i'll put this one approximately in the center of the page, but you can adjust that to fit your needs
 clock.style.position = 'absolute';
 clock.style.left = '50%';
 clock.style.top = '50%';
 clock.style.marginLeft = '-50px';
 clock.style.marginTop = '-20px';

 //set a starting time for the counter. 
 clock.time = '00:00:00';

 //display the time as div's innerHTML, using a function that formats it to look good on the page
 clock.innerHTML = get_clock_innerHTML(clock.time);

 //append the clock to the page
 document.body.appendChild(clock);

 //start a timer that will update the counter every second. You cam use other intervals if you need to
 setInterval("clock_counter('"+id+"')", 1000);
}

function get_clock_innerHTML(time)
{
 //an array that stores the symbols which draw the good old-fashioned digital clock :) 
 //IMPORTANT: don't change the alignment or anything else on this array, cause this will cause the clock to look uglier, or even not work
 var digits = " _     _  _     _  _ _   _  _    "+
     "| | |  _| _||_||_ |_  | |_||_| . "+
     "|_| | |_  _|  | _||_| | |_| _| . "+
     "                                 ";

 //put the symbols inside a <pre> tag to make sure they will be displayed just like they are written in the array.
 //you can also change the style settings i've set
 var data = "<pre><span style='color: #000; background: #ccc; font-size: 10px;'>";

 //loop trough the four 'rows' of the array and display the appropriate symbols
 for(r = 0; r < 100; r += 33)
 {
  for(i = 0; i < time.length; i++)
  {
   for(c = (time[i])*3 + r , b = 0; b < 3; b++, c++)
   {
    if(isNaN(c))
     c = 10*3+r;

    data += digits[c];
   }
  }

  data += "<br />";
 }
 
 data += "</span></pre>";

 return data;
}

function clock_counter(id)
{
 var clock = document.getElementById(id);

 //split the time into hours, minutes and seconds
 var tmp = clock.time.split(":");

 var hours = tmp[0];
 var minutes = tmp[1];
 var seconds = tmp[2];

 //if the seconds and/or minutes are about to pass 59 - increase the minutes/hours and set seconds/minutes back to zero.
 if(seconds == 59)
 {
  if(minutes == 59)
  {
   hours++;
   minutes = '00';
   seconds = '00';
  }
  else
 {
   minutes++;
   seconds = '00';
  }
 }
 else //otherwise just increase the seconds untill they reach 60
  seconds++;
 
 //update the var that holds the time
 clock.time = ((hours < 10) ? "0"+parseInt(hours) : hours)+
 ":"+ ((minutes < 10) ? "0"+parseInt(minutes) : minutes) +
 ":"+ ((seconds < 10) ? "0"+parseInt(seconds) : seconds);

 //and update the innerHTML of clock's div
 clock.innerHTML = get_clock_innerHTML(clock.time);
}
Make sure your users know how long they've been on the page, they have to eat from time to time, you know ;) You can see a demo here and get the code from here.

Javascript digital clock

Do you wanna have a clock on your pages? I bet you do. Well, there are tons of clock scripts out there, but I tried something different here. Instead of using images to represent the clock, I used symbols, just like they do in the old digital clocks. It's a bit nasty algorithm, but it sure works :)
Here is what I did:
window.onload = function()
{
 //draw the clock when the page loads
 draw_clock('current_time', 1);
}

function get_current_time()
{
 //create a new date object and get current hours, minutes and seconds
 var d = new Date();
 var h = d.getHours();
 var m = d.getMinutes();
 var s = d.getSeconds();

 //add a leading 0 (zero) to those which are one digit
 if(h < 10)
  h = "0" + h;

 if(m < 10)
  m = "0" + m;

 if(s < 10)
  s = "0" + s;

 return h+":"+m+":"+s;
}

function draw_clock(id)
{
 //create the div that will hold the clock
 var clock = document.createElement('div');
 
 clock.id = id;
 
 //you can change the style of the clock ie to position it at a specific place on the page
 //i'll put this one approximately in the center of the page, but you can adjust that to fit your needs
 clock.style.position = 'absolute';
 clock.style.left = '50%';
 clock.style.top = '50%';
 clock.style.marginLeft = '-50px';
 clock.style.marginTop = '-20px';
 
 //get the current time and set it as div's innerHTML, using a function that formats it to look good on the page
 clock.innerHTML = get_clock_innerHTML(get_current_time());

 //add the element to the page
 document.body.appendChild(clock);

 //set the timer which will update the clock. The interval can also be set to more that a second. 
 //If you need to update the time in another interval of time, say 15 seconds, you can use 15000 as the second argument to setInterval()
 setInterval("clock_current_time('"+id+"')", 1000);
}

function get_clock_innerHTML(time)
{
 //an array that stores the symbols which draw the good old-fashioned digital clock :) 
 //IMPORTANT: don't change the alignment or anything else on this array, cause this will cause the clock to look uglier, or even not work
 var digits = " _     _  _     _  _ _   _  _    "+
       "| | |  _| _||_||_ |_  | |_||_| . "+
       "|_| | |_  _|  | _||_| | |_| _| . "+
       "                                 ";

 //put the symbols inside a <pre> tag to make sure they will be displayed just like they are written in the array.
 //you can also change the style settings i've set
 var data = "<pre><span style='color: #000; background: #ccc; font-size: 10px;'>";

 //loop trough the four 'rows' of the array and display the appropriate symbols
 for(r = 0; r < 100; r += 33)
 {
  for(i = 0; i < time.length; i++)
  {
   for(c = (time[i])*3 + r , b = 0; b < 3; b++, c++)
   {
    if(isNaN(c))
     c = 10*3+r;

    data += digits[c];
   }
  }

  data += "<br />";
 }
 
 data += "</span></pre>";

 return data;
}

function clock_current_time(id)
{
 //get the new time and change the innerHTML of the clock
 document.getElementById(id).innerHTML = get_clock_innerHTML(get_current_time());
}
Now you know what time it is* :) You can see a preview here and download the code from here.

*Does anyone know what "it" means in the sentence "What time is it?" :)

Thursday, August 14, 2008

Javascript image magnifier

A friend of mine has asked me if she can put a script on her image gallery that magnifies the pictures the way that desktop software does when you zoom in. The main reason for this was that some of the people, browsing the gallery, have found it difficult to read some funny stuff like a road sign in the background of the picture. She needed something to work on the page itself, so the users won't need to save the picture on their pc and then zoom in to read this funny road sign. So, here it is, a javascript image magnifier:

I've made some settings for the the script to be more easily adjustable to what you need. The code starts with the declaration of the magnifier_settings array:

var magnifier_settings = new Array();
magnifier_settings['widht'] = 100;
magnifier_settings['height'] = 100;
magnifier_settings['zoom_level'] = 2;

The width and height indexes of the array are used to manage how big the magnifier should be. The zoom_level is, well, a zoom level :) The value in this var will be used to determine how much times the magnified image will be biger than the original one.

What fallows is a function that I've already posted about, which gets the offset coordinates of the cursor, according to the image on which it is called. This offsets will be used to determine where should the magnifier be displayed.

function get_image_offset(e, id)
{
 offset_x = e.offsetX ? e.offsetX : e.pageX-document.getElementById(id).offsetLeft;
 offset_y = e.offsetY ? e.offsetY : e.pageY-document.getElementById(id).offsetTop;
 
 magnify(document.getElementById(id));
}

The new addition to the code in this function is the call to magnify(), which is the function that does the magnification.

function magnify(elmnt)
{
 //check if the element exists; if it does not - create it
 if(!document.getElementById('magnifier'))
 {
  //create the div that will hold the magnifier
  var magnifier = document.createElement('div');
  magnifier.id = 'magnifier';
  magnifier.style.width = magnifier_settings['widht'];
  magnifier.style.height = magnifier_settings['height'];
  magnifier.style.overflow = 'hidden';
  magnifier.style.border = '2px solid #000';
  magnifier.style.position = 'relative';
  
  //magnified image. The original image is used to create the new one, which means that this function 
  //will work on any number of images on the same page, without the need to declare them or anything else..
  var magnifier_img = document.createElement('img');
  magnifier_img.id = 'magnifier_img';
  magnifier_img.src = elmnt.src;
  magnifier_img.width = parseInt(elmnt.width)*magnifier_settings['zoom_level'];
  magnifier_img.height = parseInt(elmnt.height)*magnifier_settings['zoom_level'];
 }
 else 
 {
  //if the element already existst we don't need to recreate it. Just declare the same variables, as used when creating the elements. 
  //This saves a lot of work for the browser and makes the script run smoother even on older PCs
  var magnifier = document.getElementById('magnifier');
  var magnifier_img = document.getElementById('magnifier_img');
 }
 
 //Adjust the magnifier position. Basically, it is set to the offset of the cursor plus a random value(i use 25) 
 //that will move the magnifier a little bit to the right  bottom of the page. This is used with two purposes: 
 //1. the magnifier will not pop over the cursor, so the user will actually see what will be magnified :)
 //2. this resolves an issue with the onmouseover trigger of the original image. If the value is not altered by 25, 
 //the instant when the magnifier is displayed, a onmouseout event is triggered on the original image, cause 
 //the mouse is now over the magnifier and not the original image. This causes the magnifier to be destoyed 
 //and in general is quite the oposite of what we want, cause this adds a big load to the client machine.
 //The top value is altered by the elements height, cause if the image is not at the top of the page,  
 //the magnifier will be misplaced somewhere above the image
 magnifier.style.left = offset_x+25;
 magnifier.style.top = offset_y+25-elmnt.height; 
 
 //Put negative margins to the magnified image, so the will show at the right place in the magnifier div
 magnifier_img.style.marginLeft = '-'+offset_x*magnifier_settings['zoom_level']+'px';
 magnifier_img.style.marginTop = '-'+offset_y*magnifier_settings['zoom_level']+'px';
 
 
 //Check again, if the magnifier is not created, cause if it's not we need to append it to the page elements
 if(!document.getElementById('magnifier'))
 {
  magnifier.appendChild(magnifier_img);
  
  //The only way I figured this magnification thing would work is using an image 'holder', which is a div 
  //with the same id as the  element plus the part '_holder'.
  var id = elmnt.id+'_holder';
  
  document.getElementById(id).appendChild(magnifier);
 }
}

//Removes the magnifier from tha page. This can be changed to just alter the magnifier's display property to 'none'
//or visibility to 'hidden', but i figured removing it is the most appropriate way
function hide_magnifier(id)
{
 id += '_holder';
 
 if(document.getElementById('magnifier'))
  document.getElementById(id).removeChild(document.getElementById('magnifier'));

}

And now, the HTML code that will display the images on the page:

<div id='test_holder'>
<img id='test' src='test.jpg' onmousemove='get_image_offset(event, this.id);' onmouseout='hide_magnifier(this.id)'>
</div>
<div id='test2_holder'>
<img id='test2' src='test2.jpg' onmousemove='get_image_offset(event, this.id);' onmouseout='hide_magnifier(this.id)'>
</div>
<div id='test3_holder'>
<img id='test3' src='test.jpg' onmousemove='get_image_offset(event, this.id);' onmouseout='hide_magnifier(this.id)'>
</div>

You can put as many images as you wish, they will be handled by the same function automatically. I've used 3 images to show how the script works on more that one image. You can put the code on you entire gallery or just a single image, it's your call :)

The two things required for this script to work are as fallows:

  • You need to have an id on each image. This is very important, cause otherwise the script won't work and a handful of javascript errors will occur when the user mouseover's an image that doesn't have an 'id' property. You can use whatever id you want, just use one :)
  • The second thing is a div that holds the images. This is also very important, cause the script again won't work, and again there will be many many javascript errors when you mouseover the images. The requirement here is that the id for the div is the same as the id of the image it holds, plus the text '_holder'. You can use whatever styles you want on that div. If you want to, you can also put some other stuff in it, not just the image. Again - just put the images in divs and use the same ids with the text '_holder' added to them.

I made two demos for this script with different settings. The first one is here and it uses a 100x100 pixels magnifier, with a zoom level of 2. You can download the code from here. The second one can be seen here and it uses 200x200 pixels magnifier with the zoom level of 4. You can download this code from here.

Javascript image map

Have you ever needed to know exactly where the user has pointed or clicked on an image? Well, this is easily done with HTML image maps, they are quite useful. But they do have some disadvantages. Using an HTML/XHTML image map requires form submission or page redirection to be used. What if you need to display appropriate content somewhere on the page, depending on where the user has pointed? Here is a way to get the offset coordinates of the pointer, inside an image.

function get_image_offset(e, id)
{
offset_x = e.offsetX ? e.offsetX : e.pageX-document.getElementById(id).offsetLeft;
offset_y = e.offsetY ? e.offsetY : e.pageY-document.getElementById(id).offsetTop;
 
document.getElementById('x').innerHTML = offset_x;
document.getElementById('y').innerHTML = offset_y;
}

This function takes two parameters - the event (mouseover, click, mousemove), and the id of the element (image) that we wan't to use. It saves the offset in offset_x and offset_y. If client's browser is IE, the offsetX and offsetY values will be used, but since this is not supported by the other browsers, we can use the pageX and pageY values and the elements offsetLeft and offsetTop values to determine the cursor offset.

After the two lines of code have been executed we have the offset in the variables offset_x and offset_y and we can use them for any purpose. I have added two span elements to the HTML, which show the offset as the user moves the mouse over the image. Here is the rest of the code you need to get this working:

<img id='my_image_map' src='test.jpg' onmousemove='get_image_offset(event, this.id)'>
<br />
X: <span id='x'>0</span>; Y: <span id='y'>0</span>

Now, presuming you have a 'test.jpg' file inside the folder of your page, you will see that when you move the mouse over it, the values of the two spans change width the coordinates of the cursor offset. You can change the code that alters the innerHTML of the two spans and do whatever you need to do with this offset coordinates. You can also change the event that triggers the function. I use onmousemove to update the coordinates every time the cursor moves over the image, but you can use other triggers like onclick, ondblclick, etc.

P.S. You can see a demo of this code here and you can get the example code from here