Generally, it is used to enlarge and view the pictures of goods, and it has similar effects in JD.COM Mall, Ke Fan and Alibaba.
The advantage is that you can zoom in and view the picture locally near the original picture, and you can control the viewing position with the mouse.
fundamental principle
First, there must be an img element as the original object and a container as the display box.
Put another img element in the display box as a large image object, and set the size according to the proportion.
When the mouse moves on the original picture, the corresponding part is displayed through the absolute positioning of the big picture, which realizes the effect similar to a magnifying glass.
Picture loading
When the program is initialized, the _initLoad program will be executed first, which is mainly used to load pictures.
Because the size obtained by img before loading is not accurate, the calculation of related parameters has to wait until the picture is loaded.
There are two ways to enlarge: to enlarge with the original image and to enlarge with the new image.
The advantage of enlarging the original image is that only one image needs to be loaded, and a clearer effect can be obtained by using a new image.
According to different methods, the corresponding original loader is selected:
useOrigin =! This. _ zoomPic & amp& amp this. _scale,
loadImage = $$F.bind( useOrigin? This. _loadOriginImage: this. _loadImage,this);
When the large image is not set but the magnification is available, the original image magnification loader will be used automatically.
Let's take a look at the process of enlarging and loading with the original image:
1, load the original image:
if(origin pic & amp; & amporiginPic! = image.src ) {
image.onload = loadImage
image.src = originPic
} else if ( image.src ) {
If (! image.complete ) {
image.onload = loadImage
} Otherwise {
loadImage();
}
} Otherwise {
Return;
}
The _originPic property records the address of the original image. If the original image has been set and is different from the currently loaded image of the element, onload is set and the original image is loaded.
Otherwise, if the element currently has a loaded picture, first judge whether the loading is completed through complete, and set onload not to stop. If it is finished, directly execute the loader.
Finally, if there is no original picture, exit the program.
2. Execute the _loadOriginImage loader:
This. _ image.onload = null
This. _zoom.src = this。 _ image.src
This. _ init loaded();
Because ie6/7' s gif picture loading has a bug, onload will be reset first.
Then execute _initLoaded initializes the load setting program.
Using new pictures is a bit complicated:
1, load the original image, as shown above.
2. Pre-installed big picture:
var preload = this。 _preload,zoomPic = this。 _zoomPic || image.src,
loadPreload = $$F.bind( this。 _loadPreload,this);
If (zoomPic! = preload.src ) {
preload.onload = loadPreload
preload.src = zoomPic
} Otherwise {
If (! preload.complete ) {
preload.onload = loadPreload
} Otherwise {
This. _ load preload();
}
}
_preload is a preload object, and the _loadPreload loader is used.
Pre-installed objects are mainly used to obtain the original size of the big picture, which is also the basis of the replacement skills of the original picture later.
If there is no big picture, it means that there is no big picture at present and there is no enlargement, so the original picture is used to make a big picture.
The loading method is similar to the original picture.
3. After loading the original image, execute the _loadImage original image loader:
Copy code
If (this. _loaded ) {
This. _ init loaded();
} Otherwise {
This. _ loaded = true
If (this. _scale ) {
This. _ substitute = true
This. _zoom.src = this。 _ image.src
This. _ init loaded();
}
}
Copy code
If _loaded is true, it means that the big picture has been loaded, and the _initLoaded program is directly executed.
Otherwise, set _loaded to true to mark that the original image has been loaded. If there is a custom scale at this time, replace the big picture with the original picture first.
Because large images are usually slow to load, you can immediately operate by replacing the original image first, and set the _substitute attribute to true to use the substitution flag.
4. After completing the big picture preloading, execute the _loadPreload big picture preloading program:
This. _zoom.src = this。 _ preload.src
If (this. _loaded ) {
If (! This. _substitute) {this. _ init loaded(); }
} Otherwise {
This. _ loaded = true
}
If _loaded is true, it means that the original image has been loaded; if _substitute is false, it means that the original image has not been replaced, then the _initLoaded program is executed.
If the original image is not fully loaded, set _loaded to true to mark that the large image has been loaded.
Another question about image loading, test the following code:
Copy code
& lt script & gt
Var img = new image
Functional test () {
img . onload = function(){ alert(" load ")}
img.src= "。 hk/images/nav_logo8.png "
}
Test ()
Set Timeout (Test, 3000)
& lt/script & gt;
Copy code
In chrome/safari, "Load" only pops up once, and everything else works twice. Maybe it's optimized or something.
After loading, you can set related objects and parameters, all of which are carried out in the _initLoaded program.
Load setting
Initialize the loading setup program in _initLoaded, mainly to prepare for triggering the amplification effect.
Step 1, execute the _initSize program to initialize the display size.
First, correct the magnification ratio:
If (! Scale) {scale = this. _ preload . width/image . width; }
This. _ scale = scale = math . min(math . max(this。 _min, scale), this. _ max);
If the scale is not set, the default size obtained from the preloaded objects will be used as the large drawing size.
"Safety measures" were taken when loading the picture to ensure that the magnification can be obtained here.
You can also limit the scale size by customizing the maximum and minimum attributes.
Then you can set the size of the big picture proportionally:
zoom . width = math . ceil(image . width * scale);
zoom . height = math . ceil(image . height * scale);
Step 2, execute _initViewer to initialize the display box program and set the display box.
Set the style first:
var styles = { padding: 0,overflow: "hidden" },p = $$D.getStyle( viewer," position ");
If (p! = "relatives" & amp& ampp! = " absolute "){ styles . position = " relative "; };
$$D.setStyle (viewer, style);
zoom . style . position = " absolute ";
Then insert the display diagram into the display frame:
If (! $$D.contains( viewer,zoom)){ viewer . appendchild(zoom); }
The third step is to execute _initData initialization data program, mainly to set some parameters for amplification.
Comprises original coordinates used for position judgment:
This. _ rect = $ $ d . rect(image);
Correction parameters for left/top correction:
This. _ repair left = image . client left+parse int($ $ d . get style(image," padding-left "));
This. _ repair top = image . client top+parse int($ $ d . get style(image," padding-top));
There are also range parameters and display size.
The range parameter is the size of the range to be displayed in the original image, and the display size is the display size of the display frame.
If the range parameter is customized by rangeWidth and rangeHeight, the display size can be calculated by combining the magnification ratio:
range width = math . ceil(range width);
range height = math . ceil(range height);
This. _ viewer width = math . ceil(range width * scale);
This. _ viewer height = math . ceil(range height * scale);
$$D.setStyle (viewer, {
Width: This. _viewerWidth + "px ",
Height: This. _viewerHeight + "px "
});
Copy code
If it is not set, the default display size of the display box will be used:
Copy code
Var style;
If (! viewer.clientWidth ) {
var style = viewer.style
Style = {
Display: style.display,
Position: style.position,
Visibility: styles. Visibility
};
$$D.setStyle (viewer, {
Display: Blocked, Position: Absolute, Visibility: Hidden
});
}
This. _ viewer width = viewer . client width;
This. _ viewer height = viewer . client height;
If (styles) {$$D.setStyle (viewer, style); }
rangeWidth = Math.ceil( this。 _ viewer width/scale);
rangeHeight = Math.ceil( this。 _ viewer height/scale);
Copy code
Note that the display range is obtained through clientWidth/clientHeight.
If the display box is hidden and displayed as none, you can't get clientWidth/clientHeight directly.
In this case, the program uses the following methods to obtain:
1, recording the original value of display/position/visibility;
2, set to Block/Absolute/Hidden respectively, which can be hidden or occupied;
3, obtaining parameters;
4, reset the original value, restore the original state.
After the display range is obtained, the range parameters can be obtained by matching the ratio.
Ps: This is a general method to obtain the size parameters of unoccupied elements, and the css of jquery also uses this method to obtain the width/height.
After proportional calculation, you may get a decimal, but the size can only be an integer, and the program always uses Math.ceil to round it up.
scale effect
After everything is set, you can start setting the trigger.
The program will automatically execute the start method, mainly binding the _start program to the mouseover/mousemove of the original image object:
var image = this。 _image,START = this。 _ START
$$E.addEvent( image," mouseover ",START);
$$E.addEvent( image," mousemove ",START);
Corresponding to the case of moving in and on the original object.
Ps: If you use attachEvent, you should also pay attention to the problem of repeated binding of the same function. AddEvent here does not have this problem.
The bound _start program is mainly used to unbind and bind some events:
password
To end the magnification effect when moving out of the window, bind the _OUT program to mouseout of document:
This. _ out = $ $ f.bindseventlistener (function (e) (
If (! E.relatedTarget) this. _ END();
}, this);
Mouseout is triggered when the mouse moves out of the document. If the current relatedTarget is empty, execution of _end will be delayed to end the program:
var oThis = this,END = function(){ oThis。 _ end(); };
This. _END = function(){ oThis。 _timer = setTimeout( END,othis . delay); };
In the _end program, the stop method will be executed first to delete all possible binding events, and then the start method will be executed to continue waiting for the trigger.
The _move mobile program bound by mousemove is mainly used to zoom in wherever the mouse moves.
In order to adapt to more situations (such as extended other modes), it is bound to the document, but therefore the mouseout event cannot be used to trigger the removal program.
The program compares the coordinates of the mouse and the original image to determine whether the mouse moves out of the object range of the original image:
var x = e.pageX,y = e.pageY,rect = this。 _ rect
if(x & lt; rect.left | | x & gtrect.right | | y & ltrect.top | | y & gtrect.bottom ) {
This. _ END();
} Otherwise {
...
}
If the mouse moves out of the original image object, execute _END to end the magnification effect.
If the mouse moves over the original object, coordinates will be calculated for positioning.
Firstly, correct the coordinates and convert the mouse coordinates into the positioning coordinates of the big picture:
pos . left = viewer width/2-(x-rect . left-this。 _ repair left)* scale;
pos . top = viewer height/2-(y-rect . top-this。 _repairTop) * proportion;
Set the range limit again:
x = math . ceil(math . min(math . max(pos . left,viewerWidth - zoom.width),0));
y = math . ceil(math . min(math . max(pos . top,viewerHeight - zoom.height),0));
Finally, set the positioning to make the display frame display the part to be enlarged.
Ps: I tried to locate with scrollLeft/scrollTop, but found that it would move like a sawtooth in ie, and the bigger it was, the more obvious it was, so I gave up.
Mouse scrolling and zooming
If the mouse property is set to true, the mouse scrolling and zooming functions will be turned on.
During the magnification effect, you can zoom in on the larger picture by rolling the mouse wheel.
In fact, it is to modify the magnification according to the change of dynamic parameters of the roller.
The mouse scrolling event was also mentioned in slider, but only the difference between ie and ff was analyzed at that time. Let's analyze it again here.
First, ie uses mousewheel to bind events, and uses the wheelDelta of events to get scrolling parameters.
Other browsers use the following code for testing:
password
Scroll down and you can get the following results:
ff:DOMMouseScroll:3_undefined
Opera: mouse wheel: 3_- 120
Chrome/safari: mouse wheel: 0_- 120
You can see the binding of events, ff only supports DOMMouseScroll, others only support mousewheel.
As for the acquisition of scrolling parameters, ff only supports detail and opera, and chrome/safari supports wheelDelta.
Ps: I don't understand why the details of chrome/safari are 0, and there are other uses.
Another difference between DOMMouseScroll and mousewheel is that the former cannot directly bind elements, while the latter can.
In other words, you can elem.onmousewheel, but you can't elem.onDOMMouseScroll.
According to the above analysis, in the _start program, the _mouse program is bound to the scrolling event of the document as follows:
This mouse & amp& amp$$E.addEvent (document, $$B.firefox? "dommousroll": "mousewheel", this. _ MOUSE);
In the _mouse program, a new zoom ratio is obtained according to the scrolling parameters and the user-defined zoom ratio:
This. _scale += ( e.wheelDelta? e . wheel delta/(- 120):(e . detail | | 0)/3)* this . rate;
When modifying the scale, the program parameters also need to be recalculated.
Since _rangeWidth/_rangeHeight will affect the calculation process, it is necessary to restore to the user-defined default value:
var opt = this.options
This. _ range width = opt . range width;
This. _ range height = opt . range height;
Then perform _initSize and _initData to reset the size and parameters, and then perform _move relocation.
Finally, remember to use preventDefault to prevent triggering page scrolling.