SCRIPTING:

Salma Hayek

IMAGE AND LAYER ZOOMING GALLERIES
Create a gallery of images, or of layers, encapsulating all the variables within a Class. Feature onto them either on mouse over or on mouse out, or upon whatever other type of event as a matter of fact, zooming effects.

Set the properties of these zooms. Set their speeds. Set globally of individually. Zoom in and zoom out. Reset all on the fly or with a global zooming effect affecting all the images or all of the layers.
February 2004
{ @ }
The model above is Salma Hayek - in «From Dusk To Dawn»
LOADS OF SALMA HAYEK ON THE NET


OVERVIEW
What the functions do: they are meant to manipulate width and height of objects that have such properties

This round these scripts provide significant power for the management of image (or layers) galleries, and these functions offer also a few additional features that thus far have not been available in galleries, at least as far as javascript is concerned or we know it.

These methods rely on the existence of document Objects, whatever valid Object reference is potentially suitable to be passed to these functions (as long as, we will see, these document objects have a width and height property whose manipulation makes sense).
If you assign to the image tags an id property, you can manipulate them thorough:
document.getElementById('IDhere')
That's a valid reference to an Object then.
Of course, this means that by taking avail of the latter mentioned syntax, you can pass to these functions also layers regardless of the fact whether they have or not images included: also a layer including no image whatsoever may be manipulated by these functions: the presence of an image(s) is not mission critical, it is just the most obvious case when you may want to use these scripts that is.
Keith Haring painting
A Keith Haring painting: Untitled, (1983)
Keith Haring painting
A Keith Haring painting: Untitled, (1983)
As hinted, what these functions do is to manipulate the properties:
width, height
of whatever valid Object that has such properties: and of course images have them, and also layers have them as long as the css class rule or the inline style property that defines the layer defines the width & height properties set.

That is, a first warning: to use these functions competently, in case you take avail of
document.getElementById
in order to pass to these functions the objects that must be affected, then remember that such objects must have a width and height property set to some numerical value in their style tag property (example: <span id="foo" style="width: 200; height: 100">) or in the class that rules them (example: if <span id="foo" class="fooClass">, then fooClass must define also width: 200; height: 100. Obviously enough 200 and 100 are just placeholder values for whatever different numerical value you may need to assign).

Thus, the functions can shrink or enlarge the width and height of the passed objects, affecting how many objects as you prefer: they constitute what we can therefore call a gallery with a set of methods to perform actions upon them.
Since what is affected is the width and height, these functions either enlarge or shrink the whole objects, that is they do not clip them: no portions of the objects disappear during a shrinking process, and no new portions of the objects appear suddenly in sight during a width or height manipulation, but the objects shrink or widens as a whole namely following a proportion.


CODES AND INITIALIZATION
The codes and instructions on how to initialize a gallery so to enable on it all its related manipulation methods

The functions are two and are named:
makeGallery
galleryComponent
You will use only makeGallery to initialize your gallery. makeGallery will use on its turn galleryComponent.

THE CODES
Keith Haring painting
A Keith Haring painting: Untitled, (1983)
Salma Hayek
The model above is Salma Hayek
SALMA HAYEK ONLINE
lines:
Keith Haring painting
A Keith Haring painting: For Shawus, (1984)

In order to start using the functions, you just have to run makeGallery.
It takes in one mandatory argument, which must be an array of suitable objects.

Since they must be as an array, maybe you want a more practical way to build up such argument array of valid objects on the fly, in order to pass it to makeGallery soon afterwards. A way to achieve it is the following snippet:

var myarray=new Array("id1", "id2", "id3" /*etc...*/);
/*you have an array of Strings, that must be valid assigned IDs*/

var output=new Array();
for(var i=0; i<myarray.length;i++){
output[++output.length-1]=
document.getElementById( myarray[i] ); }


You thus have an array of objects readily stored within the variable named output.
Now:
makeGallery(output);

That simple.
If by chance you pass such input array to makeGallery as an array of String names, the function will assume such string names are ids of layery and it will build up objects by itself in the shape of document.getElementById('StringName'). This stresses that prior to running makeGallery you do have to make sure your layers have been already and all loaded within the browser or errors complaining about attempts to grab still undefined layers will be triggered.
Once run, makeGallery takes care of initializing each referred item as an instance of the galleryComponent class, thus enabling each instance of taking avail of the methods stored within the galleryComponent class.

makeGallery will by default initializes a window object (that is, a globally defined variable) named gallery.
If by chance you don't like such default name or lest of name conflicts, if you pass to makeGallery a second argument, such second argument (a String) will initialize the window global variable after that name you passed as second argument. An optional feature, obviously.

Now, how do you address each newly initialized image/layer (by and large: object) so that you can trigger on it the methods stored within galleryComponent (which methods we'll list and document soon)?
The procedure has been devised to encapsulate all the initialized objects (which, being a gallery can arguably involve even scores of elements) so to avoid assigning to the window object too many variable names: they are all stored within one variable, the one named "gallery", as associative indexes.

So, all the instances belong to the globally initialized variable named gallery. BE WARNED that if you passed a second argument different than "gallery", in all the following examples you have to change "gallery" with the name you passed ok? Throughout the present documentation I assume you have not changed that and you were quite happy to use the default variable and to run one gallery (for obviously enough if you run makeGallery with another name after you have run it with the default name, what you're doing is assigning to the window scope two variable names representing two different galleries).
You address each objects as follows: if the object passed had an ID set to a value you address them by:

gallery[ 'IDhere' ]

If it had a name and no id, address them by the name. The function makeGallery will try to interrogate the object as follows:
  • Has it an ID? Use such ID as the identifier of this instance within gallery. So:
    gallery['anId1']; gallery['anId2']
  • No ID? Use the word "component" plus a number ranging from zero included onward; use such words as the identifier of this instance within gallery So:
    gallery['component0']; gallery['component1']; etc...
To trigger a method on it, say the method named zoom:
gallery['IDhere'].zoom()

Did you guess what this method named "zoom" does onto layer or image "IDhere"?
I think so, so now it's time to document all the methods you can call upon these objects. They are the methods that animate your galleries!


METHODS OVERVIEW
Documentation about the purposes of all the available methods

AVAILABLE METHODS
[one object methods and collective methods]
One object methods
These methods affect only the object they're called upon:
gallery[ 'IDhere' ].METHOD()
Method() would affect only the 'IDhere' object.
isRunning
This is NOT a method, and I apologize for this early exception, but that is a mere property. It may be important you know that by interrogating whether
gallery['IDhere'].isRunning
is equal to 1 or not you may know whether an object is still undergoing some zooming process and has not been stopped (yet). If it equals 1, it is still running & therefore undergoing some zooming process.
isRunning is case sensitive.
stop()
It stops the zooming effects, whatever they are, upon the referred object (image, layer...).
It restores isRunning to zero.
zoom()
This triggers the zooming effect on an image/layer (object).
To know how to trigger different types of zooms, see the other methods which set the details.
If isRunning is set to zero, it triggers and sets it to 1, otherwise if isRunning is set to one, it does not trigger. Also, it does not trigger if isBlocked is set to 1.
block(all)
This prevents the referred object from undergoing a zoom effect even if the occurred event/command would have triggered it. It basically allows for exceptions!

To achieve this it updates a property named isBlocked from zero to 1 as well.
If the argument all is passed as number 1, blocks all the objects.
isBlocked
This is NOT a method but a property. It is triggered and changed from the default zero to number 1 when block() is called.
isBlocked is case sensitive.
unblock(all)
Complements the method block(); the unblock method unblocks an object, thus reinserting it within the default flow of objects affected by the zooms. It achieves that by simply resetting isBlocked to zero.
If the argument all is passed as number 1, unblocks all the objects.
setLimit(Number)
You may arguably want your zooms to stop after a certain size has been reached. If you don't set a limit, the zoom will be infinite, unless you call stop() of course.
Pass to this function a number, which will represent the maximum width the object is allowed to reach upon zooming on it, and the method will ensure that upon zooming it as soon as such limit has been attained, the zoom effect would autostop.

Of course, such number can also represent the minimal width the object is allowed to shrink into: it all depends on what type of zoom you've enabled for this object or for this round, whether either a zoom in or a zoom out zoomer.
You'll see soon what method determines this.
setSpeed(Number)
This method determines the speed of your zooming effects. It is set to the passed Number, which must represent the milliseconds after which the object must zoom in or out; that is, it will gradually enlarge or shrink accordingly to steps that recur at that given amount of milliseconds.
Default speed is 100 milliseconds.
setZoom(Number)
This method determines the type of zoom: to enlarge (zoom in) pass to it as argument Number 1. Pass 0 to zoom out.
WARNING: do pass the number, even if it is meant to be zero. The default behaviour of the objects is to be zoomed in.
setIncrease(Number)
This method determines the amount of pixels you want to zoom in or out at each iteration. Pass such amount as a Number. I think it is self evident this is an important feature. The default is 10 (pixels).
The increase is meant as the increase on the width. YOu see, a choice had to be made between width and height, and since each zoom is strictly proportional in its progressions to maintain the original width/height ratio, you can determine the increasing value only of one of them but not of both: the second property, having to be proportional, is self deduced!
setAll(ZoomType, Speed, Limit, Increase)
A convenient method to pass all the values with one single method. The arguments are, I believe, self descriptive if you've read about the methods above.
reset()
Instantaneously restores the object's width and height to the original values it had upon inception. Such values are self deduced by the size the object had when originally created.
It does not trigger if isBlocked is set to 1.
fullReset()
Instantaneously restores the object's width and height to the original values it had upon inception. Such values are self deduced by the size the object had when originally created.
What differentiates it from reset is that whereas reset would only restore the width and height of the object, this would restore all, including for instance the zoom type to the default 1, the increase value to the 10 pixels, the default speed to 100 milliseconds.
It does not trigger if isBlocked is set to 1.
Collective methods
These methods affect all the objects though called from within one single instance:
gallery[ 'IDhere' ].METHOD()
Method() would affect all the objects in the gallery, not only the 'IDhere' object.
massStop()
It stops the zooming effects, whatever they are, upon all the objects in the gallery.
massReset(Number)
It runs the method reset() upon all objects.
If you pass the argument as 1, it will run on all the objects fullReset()
It does not trigger for the objects whose isBlocked property is set to 1.
gradualReset(All, speed, increase)
The reset methods described thus far, all instantaneously reset.
This gradual reset method is gentler: the resetting process will happen as a zooming out (for zoomed in objects) and a zooming in (for zoomed out objects) after a timeout that would simulate sort of a slower animation. I included it because a sudden reset may seem too abrupt and not too nifty.
If you pass the first argument "all" as number 1, the gradual reset would apply to all objects, if passed as zero will affect only the referred object it is called upon from.
The other two arguments can set a different increase and speed amount for the resetting process, if you wish so.
It does not trigger for the objects whose isBlocked property is set to 1.
massZoom()
Zooms all of the objects after the type of zoom set for each of them.
It does not trigger for the objects whose isBlocked property is set to 1.


INVOKE ON EVENTS & THE TEST FORM
How to trigger the methods from events, and the test form to try them

To call your methods, you set an event on your images or layers such as for instance:
<img src="foo-gif" onMouseOver="" onMouseOut="">

There is no reason to be limited to that type of events, though they're going to be, arguably, the most widely used. In the test form I will use them (zooms on mouse over, quits zooming on mouse out) plus onClick from a few buttons.

The statement that each event handler must carry is the whole set of actions you want to take place upon that event, for instance:



Of course, nothing prevents you from nesting all those statements within a function and just passing the values; so, just an instance:

function foo(name){
gallery[name].setall(0,250,50,5);
gallery[name].zoom();
}

Then on your image:
onMouseOver="foo('imm1')"

TECHNICAL NOTE: Alternative Route to Events

This is a truly technical section which covers a relatively advanced topic. Skip if uninterested.

There is a much faster way to set the behaviours that must be displayed when an event x occurs, rather than that of painstakingly setting event declarations (often more than just one!) per each image or layer tag (imagine having 30 or 50 layers, as a gallery easily includes).

You proceed as follows.
Create a function that recursively iterates through all the layers or images you want to set an event for. Instance:

The function above, which is just 7 lines and is massively assigning events that would have required as many as thrice those lines if singularly included within each affected html tag (or 20 times those lines if affecting 20 layers...), is a function that takes in three arguments: the first an array with listed the IDs of your objects, the second a String of the event you want to set (say: "onMouseOver"), the third the name of the function you want to trigger upon that event.
Minor variations are possible.

The function above grabs the objects by the passed ids (assuming they're passed as an array) with the syntax you're familiar with:
document.getElementById('IDhere')

Then the function could assign to each of them the event (second argument) either by appending it by a dot or by passing it as an associative index between square brackets.
This is all fully valid syntax, not my inventions.

When you declare an event into a tag, you're appending the event to the tag object as a property that belongs to it, in the very same way you'd append to it, for instance, the name property if you include such property in the tag: the fact events are dynamic properties and not static ones, should not mislead your conception: properties can be both primitive data type and functions in java(script).

As a matter of fact events on a tag, being javascript an object oriented language aren't but properties already appended to that tag they're declared upon, which is therefore considered as an object ("objects" aren't but data structures that conglomerate properties), and thus such properties can be accessed either as (let's imagine the event is onMouseOver):
document.getElementById('IDhere').onmouseover
or as:
document.getElementById('IDhere')["onmouseover"]
The former syntax takes avail of the taditional dot syntax, the latter of the array syntax, but they are truly authentic synonyms.

The only thing that matters, is that the event considered as a property of the object is lowercased.
Indeed the event is a property of the tag when we declare it onto the tag, for the html TAG is the object that holds and owns the event as a property among all the other properties it collects.
Yet the event is lowercased because any property name is actually lowercased: it is the flexibility of the tag which, being exposed to the frontline of the end users, has been arranged by the programmers so to allow for accepting its properties in whatever case format so to make it a bit more "(final) user friendly": but upon execution, any event property name is "secretively" reconverted to lowercase. To get persuaded of that, try this:



Once on an object its event has been addressed as a property, it is possible to assign custom functions to it precisely in the very same way you assigned them inline an html tag - don't get fooled by the fact now we do it via script!
These functions are obviously meant to be the behaviour that must occur on that property (event) in the very same way they would have performed if they would have been assigned directly inline the tag.
You need therefore to have custom functions that define what to do, exactly as you needed to have them when you were calling them from within a tag property such as onMouseOver="blabla()".

More: when you assign a function on the run via script and not via tag, you must omit the parenthesis from the function assignement:
document.getElementById('IDhere').onmouseover=foo()
If you'd add the parenthesis, that would tantamount not to assign the function to the property, but it would amount to a request to actually trigger the function right now, right here, right away!
This is where a belated difference between assigning via tag or via script comes to the fore: since a tag takes in the javascript declaration in between quotes, it is a non compiled version of the function call, and thus is delayed: it can afford adding the parenthesis for it is a String, not the actual function yet; the whole tag, as a matter of fact, is like a big string encapsulating all its data. So the function inline the tag property will be turned into the actual function (that is, the string gets compiled as "geeks" would phrase it) only and exclusively when the event occurs. Only then it gets actually compiled and turned into executable code, and since such executable code carried a parenthesis set in its string version, now that it is turned from string to execution the function is triggered: it had the parenthesis.

Thus the correct via script statement to assign functions to be executed upon events is, like those included in our example snippet assignEvent above, the one achieved excluding the parenthesis: this is not a string anymore, this is a script and thus we're manipulating the real objects and not stringed and uncompiled versions of their names. So:
document.getElementById('IDhere').onmouseover.foo /*NO parenthesis!*/

You may be wondering the lack of parenthesis may prevent you from passing any arguments to foo. It does not really, if you work object oriented. Since your foo function is tailored as follows:

you have done the trick: since the foo function is to be passed as what has to be triggered upon a certain event, it overtook the event as a property of the object, and "replaced" it; thus it can make use of the keyword this to address the owner of the property (that is, of the event in this case, for an event is a property. And since our event has been set as equal to the function, the two properties, the event and the custom function, now coincide). And since the owner of the property is the object itself, the keyword this in such appended function backtracks and refers exactly to such object and thus it can interpellate it and even draw from it its ID.

Trick done, gallery[this.id] is therefore a valid reference to one of our gallery items, and then can be called using one of its methods on it.

Here is for your convenience and as an example how I initialize the events on these layers on this very same file:

Only caution: such functions must not be called before the objects they refer are fully loaded in the browser. So, just declare them or trigger them physically after the document location where you've written the implied tags/layers.

IMPORTANT: remember that if you assigned an ID to an image, the document.getElementById statement manipulates the width and height not as they have been set in the image width and height properties, but as such properties have been set in the style declaration or css rules affecting that image or layer. Thus, you have to, if necessary, re-declare them also in the style property or in the css rule affecting such ID/object.
Also, don't run makeGalleries before your layers have been loaded within the browser: call it wherever but after the position where they have been declared in your html document.
Also, remember that if you want to change the values on the fly via script, before making such changes you may want to consider making a call to stop on the object so not to interfere with ongoing processes; anyway the methods are already crafted by and large so to call in stop() before triggering whatever subsequent action.
The processes named gradualReset won't accept further zooms until they are fully performed (that is, until the object has not reached again the original dimensions that gradualReset is aimed to make it reach).

Eventually, keep in mind two common errors:
  • Zoom in, yet you set the limit to a low number: the contradiction is that you cannot have as a limit a limit which is already inferior to the purpose.
  • Zoom out, yet you set the limit to a high number: the contradiction is that you cannot have as a limit a limit which is already superior to the purpose.
In both cases the functions set the limit to the original width of the object to avoid nasty things like, for instance, infinite enlargements. Since the limit is set to the original width, no effect will take place: if the object was to be zoomed in, the limit is already attained since it was automatically set to the current (original) width; if it was to be zoomed out, as well. This would override whatever limit you may have previously set, and if you made that mistake you have to correct it by resetting a brand new and proper limit in order to see your zooms work again. You will have to reset also the increase factor.
In short, be sure you don't make that type of error. If you zoom in, the limit must be higher than the current size; if you zoom out, it must be lower than the current size. Makes sense!

Here is an oversimplified test gallery form, with three images only. Have fun, it will make you laugh.

TEST FORM
[onMOuseOver: zoom
onMouseOut: gradualReset (only the object)
onClick: stop/zoom]
COLLECTIVE ACTIONS:
[massReset(not full)]

gradual reset speed: gradual reset increase:
Block/Unblock items upon selection:
Andre Kertesz photo
an Andre Kertesz photo, Washington square, New York (1954)

Zoom (1/0): Increase:
Set Limit: Set Speed:

Katalina Verdin
The model above is Katalina Verdin

KATALINA VERDIN ONLINE


Zoom (1/0): Increase:
Set Limit: Set Speed:

Wynn Bullock photo
a Wynn Bullock photo, The Bird (1958)

Zoom (1/0): Increase:
Set Limit: Set Speed: