Categories
Technology

Demonstrating Photoshop Functionality with X-Objects

Copy found at Wayback Machine Archive.

I upgraded my original cross-browser DHTML objects into the new X-Objects — with support for Mozilla and Navigator 6.0.

To try out the new objects, I migrated 4 DHTML demos into using the new objects. These demos demonstrate different aspects of using Adobe PhotoShop’s photo filters and editors. I’ll be going over each demo in this article, but first, I wanted to describe another set of JavaScript objects used in the examples: the Animators.

Animator scripting objects

When I first started working with DHTML, and creating DHTML effects, I used to manually code animations within the page where the animation displayed. These animations used a JS timer created using the function setTimeout.

For instance, my first DHTML animation was about an animated menu that didn’t do much more than move pieces of the menu around the Web page (see animated menu). This example has changed based on new versions of both IE and Navigator, but for the most part the animation starts once the page is loaded, and continues until the last animation step is reached:

function MoveObjects() {
   theobjs["menu1"].objMoveAbsolute(
		TimingObjectsX[0][currentTick], 
                TimingObjectsY[0][currentTick])
   theobjs["menu2"].objMoveAbsolute(
		TimingObjectsX[1][currentTick], 
                TimingObjectsY[1][currentTick])
   theobjs["menu3"].objMoveAbsolute(
		TimingObjectsX[2][currentTick], 
                TimingObjectsY[2][currentTick])
   theobjs["menu4"].objMoveAbsolute(
		TimingObjectsX[3][currentTick], 
                TimingObjectsY[3][currentTick])
   theobjs["menu5"].objMoveAbsolute(
		TimingObjectsX[4][currentTick], 
                TimingObjectsY[4][currentTick])
   theobjs["menu6"].objMoveAbsolute(
		TimingObjectsX[5][currentTick], 
                TimingObjectsY[5][currentTick])


   currentTick++
   if (currentTick < 8) 
      setTimeout("MoveObjects()", 400)
}

I’ve also used setInterval as well as setTimeout to create repeating timers as well as non-repeating ones.

After a while, I started creating more complex animations such as DHTML demonstrations of how a hurricane forms, or the Dr. Dotty games, covered in a previous InterActZone article. One thing I found out is that the amount of code to control multiple objects in a synchronized animation was enormous and I got a bit tired of coding and re-coding the same timer synchronization efforts.

So, I created what I call the Animator objects. This set of objects provides for most major types of DHTML animation — movement, clipping, visibility, ordering, and sliding (combination of movement and clipping) — and has built in animation synchronization. So, you can have an animation sequence that moves 3 DIV blocks around the page, while a fourth block is being clipped and a fifth block is being hidden.

You can take a look at the Animator script file as I go through how the objects work.

How Animators work

There are three types of Animation objects used to build an animation.

First, an Animation Sequence is created. An Animation Sequence is a container for several different animator objects, all of which are animated as a unit. To create the Sequence object, use the following:

      seq = new animatorSequence();

Once the Animator Sequence is created, then Animators are added. An Animator adds a specific animation effect over a specified period of time, and over a specified number of steps. So, if I want an animation to last 100 microseconds, and occur over 15 steps, I would create the following Animator:

      var anim = seq.newAnimator(15,100);

I can add more than one Animator to a sequence, and each Animator is played in turn, as they are added to the sequence.

Once the Animator object is created, Animations can be added to the object. For instance, to move two different Web page DIV blocks at the same time, I would use Animator code similar to the following:

anim.addAnimator(theobjs["box1"],"M",160,320);
anim.addAnimator(theobjs["image2"],"M",-240,320);

In this, two DIV elements, named “box1” and “image2”, are moved at the same time, so they’re added to the same Animator. Each Animation is defined by the animation type — move type is defined with a letter “M” — and any characteristics of the animation, such as the end location of the move.

I could at this point add more Animator objects (there really is no limit to the number of Animators added to an Animation Sequence, other than limits within the underlying JS, such as array elements and number of timers). I could also add more Animations to the current Animator.

When I’m finished defining the existing Animation Sequence, I can then play it:

    seq.play();

What happens is that the animation starts, beginning with the first Animator added to the sequence, and continuing, in order, until all of the Animators have been played. Additionally, when an Animator is associated with more than one HTML element, the DHTML effect assigned is applied to each HTML element, in turn, in a synchronized manner over all of the steps of the animation.

The types of animations currently implemented are:

  • Clipping: addAnimator(theobj, “C”, newtop, newleft, newbottom, newright)
  • Movement: addAnimator(theobj, “M”, newtop_position, newleft_position)
  • Visibility: addAnimator(thobj, “H”) //Hide, use “S” for show
  • Display: addAnimator(theobj, “D”, display_type) // “block” or “none” for display
  • Z-Order: addAnimator(theobj, “Z”, z-order)
  • Replacement: addAnimator(theobj, “R”, replacement_string) // based on innerHTML
  • Parm_Replace: addAnimator(theobj, “P”, tag, classname, id, contents) // parameterized replacement
  • Slider: addAnimator(theobjs, “SL”, sliding_value, sliding_direction)

The Slider has a type of “SL”, but anything will do — it is the default animation. The first parameter is the type of slider (top to bottom, left to right, right to left, or bottom to top), and the direction specifies which way the slide will move. Note: The Slider has not been converted to working with Mozilla/Navigator 6.0 and may actually be deactivated from the Animators at some point.

Next up, we’ll use both the Animators and the X-Objects to create the PhotoShop demos.

Correcting a Photo

The first PhotoShop DHTML demo is based on using PhotoShop’s various tools and techniques to correct a bad photo. This demo is the simplest of the PhotoShop animations — using CSS absolute positioning and visibility, as you can see by accessing the Example page and picking the first demo.

To create the DHTML effects, the X-Objects and Animators are added to the page first:

<!-- cross-browser objects -->
<SCRIPT; src="cbobjects.js" language="javascript" 
type="text/javascript">>
</SCRIPT>

<!-- animation and sequence objects -->
<SCRIPT; src="animator.js" language="javascript" 
type="text/javascript">
</SCRIPT>

The content of the page is added, next. To ensure that the page’s DHTML effects work with Navigator 4.x as well as Mozilla/Navigator 6.0 and IE, all animated content is enclosed in CSS absolutely positioned DIV blocks:

<DIV; id="top" style="position:absolute; left: 20; top: 50; 
       width: 600;visibility:hidden">
Unfortunately, most photos do not turn out as we would like,
 or at least as much as I would like. Usually I'll re-take
 the photo, but sometimes this isn't feasible, or I like
 most aspects of the photo and hate to 
lose the shot. Enter Photoshop to the rescue. 
</DIV>

Once the content has been added, code is added to handle user actions. As the demo is opened into its own browser window, to close this window, the user can press the Space Bar. Additionally, hitting the ENTER key will cause the PhotoShop demo to proceed to the next “slide” in the DHMTL effect. As both actions are based on keyboard events, the keyboard events are captured and assigned to a event handler function:

   // capture events
   if (navigator.appName == "Microsoft Internet Explorer") {
	wdth = document.body.clientWidth;
	}
   else if (navigator.appName == "Netscape"){
	wdth = window.innerWidth;
   	document.captureEvents(Event.KEYPRESS);
      }
   else
      document.addEventListener("keyup",keypress,true);


   // assign function to event handler
  if (navigator.appName != "Mozilla")  
    document.onkeypress=keypress;

The event handler function pulls the keyCode from the event, and tests to see if the space bar or the ENTER key has been hit. If the space bar is hit, the page is closed. If the ENTER key is hit, the next slide is played if the demo is not at the last slide already :

function keypress(e) {
   if (!canbeginnow) return;

   if (navigator.appName == "Microsoft Internet Explorer") 
      tmp = window.event.keyCode;
   else if (navigator.appName == "Navigator")
	tmp = e.which;
   else if (navigator.appName == "Mozilla")
       tmp = e.keyCode;
   
   // if space bar hit
   if (tmp == 32) {
	window.close();
	return;
	}
   if (tmp == 13) {
      if (slide == MAX_SLIDES) 
	   return;
      next_slide();
      }
}

The code for the demon’s Animation Sequence is added next. There’s only one used for this PhotoShop demo — the animation played at the end of the demo. Its Sequence and Animators are created and played within one function:

// create animation sequence
function do_animation() { 

      // create new sequence
      seq = new animatorSequence();

      // add animator objects to sequence
      var anim = seq.newAnimator(20,100);

      // add animators
      anim.addAnimator(theobjs["image1"],"M", 200, 20, 0, 0);
      anim.addAnimator(theobjs["image2"],"M",-214,-300,0,0);
      anim.addAnimator(theobjs["image3"],"M",-214,500,0,0);
      anim.addAnimator(theobjs["image4"],"M",200,340,0,0);

      anim = seq.newAnimator(1,100);
      anim.addAnimator(theobjs["top"], "H", 0,0,0,0);
      anim.addAnimator(theobjs["top2"], "S", 0,0,0,0);
 
      anim = seq.newAnimator(20,100);
      anim.addAnimator(theobjs["image1"], "M", 150, 20, 0, 0);
      anim.addAnimator(theobjs["image4"], "M", 150,325,0,0);
     
      
      // play sequence
      seq.play();
}

There is only one Animation Sequence created, and contains 3 separate Animators. The first moves Animator is played over 100 ms, and consists of 20 steps. In this Animator, two of the demo page’s images are moved “off screen” (beyond page boundaries), and the remaining 2 are lined up next to each other. The second Animator consists of 1 step: hiding current text at top of demo page, and showing new text. The last Animator again is played out over 100 ms, and 20 steps, and this animation again moves the two images that are still showing on the page. After the Animation Sequence is created, and the three animators are added, the sequence is immediately played.

Finally, the code to handle each demo “slide” is added:

// play next presentation slide
// until last slide
function next_slide() {

   // return if animation is playing, or past last slide
   if (animatorPlaying) return;

   if (slide == 5) {
	alert("That's the end of the demonstration. 
               Re-load page to run again.");
	return;
      }

   theobjs["text" + slide].objHide();
   slide++;
   if (slide <= 4) {
    theobjs["image" + slide].objShow();
    theobjs["text" + slide].objShow();
    }
   else if (slide == 5) { 
    theobjs["text4"].objHide();
    do_animation();
    }	
}

Each “slide” consists of an image and text that are hidden together, or shown together. Notice that after the last slide is shown (slide 5) that the animation is then run.

Again, try out Demo1 from the the Example page. After clicking through all of the slides, you’ll trigger the animation. Note that it plays three separate animations, each after the other.

The next PhotoShop animation uses the tools layering ability to create a double image.

Creating a Double Image

The concept of “layers” existed in graphics, and particularly in PhotoShop long before they appeared in DHTML. An image can consist of more than one layer, with each layer having different content, color, what have you, but all of the layers combined forming the image.

A fun use of Adobe PhotoShop layers is to create a double image, and the second PhotoShop DHTML demo presents this, as you can see for yourself by accessing Demo 2 from the Example page.

 

Again, as with Demo1, the Animator and X-Object JS files are added to the page, and event handling is added. This doesn’t change from the previous example, so the code is ommitted.

In this new demo, there are several animation sequences, which are created individually as part of an array:

// setup animations
function animationSetup() { 

seq[0] = new animatorSequence(); 

var anim = seq[0].newAnimator(1,100);
anim.addAnimator(theobjs["top"],"H");
anim.addAnimator(theobjs["top1"],"S");
anim.addAnimator(theobjs["box1"],"M",160,wdth);
anim.addAnimator(theobjs["box1"],"S");

anim = seq[0].newAnimator(20,100);
anim.addAnimator(theobjs["box1"],"M",160,320);
anim.addAnimator(theobjs["image2"],"M",-240,320);
  
seq[1] = new animatorSequence();

var anim = seq[1].newAnimator(1,100);
anim.addAnimator(theobjs["top1"],"H");
anim.addAnimator(theobjs["top2"],"S");

anim = seq[1].newAnimator(5,110);
anim.addAnimator(theobjs["image1"],"M",160,145);

anim = seq[1].newAnimator(10,110);
anim.addAnimator(theobjs["image1"],"M",160,320);
anim.addAnimator(theobjs["image3"], "C",0,0,193,248);

anim = seq[1].newAnimator(1,100);
anim.addAnimator(theobjs["image1"], "H");
anim.addAnimator(theobjs["box1"], "H");

seq[2] = new animatorSequence();

anim = seq[2].newAnimator(1,100);
anim.addAnimator(theobjs["image2"],"M",160,-260);
anim.addAnimator(theobjs["image2"],"S");
anim.addAnimator(theobjs["top2"],"H");
anim.addAnimator(theobjs["top3"],"S");

anim = seq[2].newAnimator(20,100);
anim.addAnimator(theobjs["image2"], "M",160 ,60);

seq[3] = new animatorSequence();

var anim = seq[3].newAnimator(1,100);
anim.addAnimator(theobjs["top3"],"H");
anim.addAnimator(theobjs["top4"],"S");

anim = seq[3].newAnimator(5,100);
anim.addAnimator(theobjs["image3"],"M",160,310);

anim = seq[3].newAnimator(20,100);
anim.addAnimator(theobjs["image3"],"M",160,60);
anim.addAnimator(theobjs["image4"],"C",0,0,214,250);

anim = seq[3].newAnimator(1,100);
anim.addAnimator(theobjs["image3"], "H");
anim.addAnimator(theobjs["image1"], "H");

seq[4] = new animatorSequence();

var anim = seq[4].newAnimator(1,100);
anim.addAnimator(theobjs["top4"],"H");
anim.addAnimator(theobjs["top5"],"S");

anim = seq[4].newAnimator(10,100);
anim.addAnimator(theobjs["image4"],"M",110,180);
    
anim = seq[4].newAnimator(1, 100);
anim.addAnimator(theobjs["image2"], "H");
anim.addAnimator(theobjs["image3"], "H");
anim.addAnimator(theobjs["image4"],"H");
anim.addAnimator(theobjs["image5"],"S");
}

As you can see, there are 5 different animation sequences defined, for the 5 different slides of the DHTML demo. By using an array, only one sequence is played at a time.

This demo uses clipping. At this time, clipping as defined for IE 4.x and 5.x as well as Navigator 4.x, has a different frame of reference than that for Mozilla/Navigator 6.x. Because of this, in my current examples I test for the type of browser and use different clipping values based on the findings within the X-Objects (read more about clipping in X-Objects: Clipping).

Playing each slide of this demo actually plays each Animation Sequence as it is defined within the animation array:

// play next presentation slide
function next_slide() {
   if (animatorPlaying) return;
   if (slide > 4) {
	alert("That's the end of the demonstration. 
               Re-load page to run again.");
	return;
      }
   seq[slide].play();
   slide++;

}

Again, try out Demo2 from the the Example page.

Cropping a Photo

The third Adobe PhotoShop DHTML demo demonstrates how to use cropping within this tool. The DHTML used is primarily clipping with some movement, as well as hiding and showing content. I won’t repeat the code here, but you can see Demo3 yourself from the Example page. To see the demo code, choose View…Source from the browser menu.

Using the Rubberstamp tool to correct a background

The third Adobe PhotoShop DHTML demo demonstrates how to use cropping within this tool. The DHTML used is primarily clipping with some movement, as well as hiding and showing content. Again, I won’t repeat the code here, but you can see Demo4 yourself from the Example page. To see the demo code, choose View…Source from the browser menu.