3D image display space implemented by JavaScript (3 DRoom)

Source: Internet
Author: User

The program simulates such a three-dimensional space, and the images in the space are displayed according to the three-dimensional coordinates.
I have seen a 3DRoom effect a long time ago and it is implemented using complex computing.
After studying the css3 transform in the previous image transformation, we thought of a simpler method to implement it.
Compatible with: ie6/7/8, firefox 3.6.8, opera 10.6, safari 5.0.1, chrome 5.0

Effect Preview

3 DRoom

Program description

[Implementation principle]

The key to 3D effects is the implementation of depth.
Consider a 3D container as a space composed of multiple layers of different depths. The size of these layers is the same as that of the container by default.
The depth of the image is placed in the layer, and each layer scales and Transforms Based on the depth changes, resulting in a visual depth difference.
The scaling ratio changes gradually according to the ratio of the nearest point to 1 and the farthest point to 0.
The key point is that the size and coordinates of the image in the layer must be transformed along with the layer at the same time. This can be achieved through the css3 transform.
In this way, you only need to set the size of the image and set the position relative to the layer. This avoids the trouble of constantly adjusting the image size and positioning as the depth changes.

[Image loading]

After the program is initialized, you can call the add method to add images.
The add method has two parameters: Image address and parameter object. An image operation object is returned.
The operation object contains the following attributes and methods to facilitate image operations:
Img: image elements
Src: Image address
Options: parameter object
Show: Image Display Method
Remove: how to remove an image
Options can be set to the following attributes:
Attribute: Default Value // description
X: 0, // horizontal displacement
Y: 0, // vertical displacement
Z: 0, // depth
Width: 0, // width
Height: 0, // height
ScaleW: 1, // width scaling ratio
ScaleH: 1 // height scaling ratio
X and y are the displacement parameters of both water and vertical coordinates. The coordinate origin is in the middle of the bottom of the container, the horizontal coordinate is right, and the vertical coordinate is up, in the unit of px.
While z is the depth, which is used for proportional calculation. The direction is from the near point to the origin point.
Coordinate System:

After the image is loaded successfully, the _ load image loading program is executed.
First, set the image style according to the parameters:

Copy codeThe Code is as follows: img.style.css Text = "position: absolute; border: 0; padding: 0; margin: 0;-ms-interpolation-mode: nearest-neighbor ;"
+ "Z-index:" + (99999-z) + "; width:" + width + "px; height:" + height + "px ;"
+ "Left:" + (clientWidth-width)/2 + opt. x)/clientWidth * 100). toFixed (5) + "% ;"
+ "Top:" + (clientHeight-height-opt. y)/clientHeight * 100). toFixed (5) + "% ;";

Absolute positioning is required, and the width and height can be set according to the parameter.
Left and top are calculated based on the coordinate parameters. The percentages are used here, which will be detailed later.
Add a _ z attribute record depth to the image for easy calling.
At last, insert the corresponding z layer and re-display it.

[Layer Transformation]

After the image is loaded, the _ insertLayer program is used to insert the image to the corresponding layer.
_ InsertLayer has two parameters: Image Element and z depth.
The program uses the _ layers object to record the corresponding layer elements with the z keyword.
If no layer has been created for this depth,:

Copy codeThe Code is as follows: layer = document. createElement ("div ");
Layer.style.css Text = "position: absolute; border: 0; padding: 0; margin: 0; left: 0; top: 0; visibility: hidden; background: transparent; width: "+ this. _ clientWidth + "px; height:" + this. _ clientHeight + "px ;";

The coordinates and dimensions of the layer must be the same as those of the container, because the coordinates of the inserted image are defined relative to the container, which makes it easier to use.
A _ count attribute will also be added. The number of images contained in the record layer will be inserted to the container and recorded to the _ layers object.
After obtaining the layer object, insert the image into the layer and add the _ count to 1.

Then, you can use the _ showLayer program to display the corresponding Layer Based on the depth.
The program contains three coordinate attributes: _ x, _ y, and _ z, which indicate the offset of the 3D coordinate of the container.
First, use the _ getScale method to obtain the zooming scale of the z depth.
If the ratio is greater than 1, it indicates that the image is invisible after the visual depth, so it is hidden. If the ratio is smaller than 0, the image is hidden when it is invisible.

The offset of _ x and _ y also needs to be re-calculated based on the depth. The program has two kinds of Offset methods: the distance is fixed and the near point is fixed.
The point-to-point fixation means that the offset of the Plane Displacement gradually decreases with the depth, resulting in the moving direction of the point with the farthest point. The point-to-point fixation is the opposite.
To achieve this effect, as long as the displacement offset also changes with the ratio, that is, the offset is proportional to the ratio when the distance is fixed, and the offset is inversely proportional when the distance is fixed:

Copy codeThe Code is as follows: var moveScale = this. fixedFar? Scale: (1-scale );

Then, the parameters are handed over to the _ show program for processing and the results are displayed.

To maximize the use of layer elements, the program will put the layers without images in the _ remove image removal program into the _ invalid discard layer set. When the layer needs to be inserted, priority is obtained from _ invalid.

[Scaling ratio]

As mentioned above, the scaling ratio should change gradually according to the latest point as 1 and the farthest point as 0.
The program is calculated by the following formula by default:

Function (z) {return 1-z/1000 ;}

However, when we use this formula to implement the 3DRoom effect, we will find that the ratio changes are too fast and not as stable as the 3DRoom.

After studying the code, we found that the original formula is as follows:

This. r = FL/(FL + (z * Z ));

FL and Z are constants, that is, the formula can be expressed:

Function (z) {return 1/(1 + z/constant );}

According to this formula, when the depth is 0, the ratio is 1, when the depth is constant, the ratio is 0.5, and when the depth is infinite, the ratio is 0.

For the change effect, see the following procedure:

<P> formula: <input id = "idFormula" type = "text"> <input id = "idFRun" value = "execute" type = "button"> <input id = "idFClear" value = "clear" type = "button"> <input id = "idFDefault" value = "Default formula" type = "button"> <input id = "idF3DRoom" value = "3DRoom Formula "type =" button ">
[Ctrl + A select all Note: If you need to introduce external Js, You need to refresh it to execute]

It can be seen that the scaling ratio changes evenly by default, while the 3DRoom formula is fast first and then slow, and gradually slows down, so it feels stable.
According to the actual situation, you can also design the appropriate formula as long as it complies with the change between 1 and 0.

[Css3 mode]

There are three scaling methods in the program: css3, zoom, and base. The program structure of the mode is similar to that of the previous article.
The purpose of scaling transformation is to display the scaling effect based on the passed ratio and position offset to achieve the final 3D effect.

The css3 mode uses the css3 transform. in the previous article, we have introduced how to use the matrix of the transform for scaling and rotation. This time, we need to perform location transformation with the next two parameters.
Pay attention to the unit settings for the following two parameters. In MDC's-moz-transform, the descriptions are as follows:
Gecko (Firefox) accepts a <length> value for tx and ty.
Safari (WebKit) and Opera currently support a unitless <number> for tx and ty.
This parameter indicates that the tx and ty parameters must contain units in Firefox, while WebKit and Opera only need numbers (excluding units, the default is px ).
The Program sets the unit according to the browser.

In css3 mode, you can also modify the _ r radian attribute to rotate.
Finally, set matrix to implement transformation:

Copy codeThe Code is as follows: layer. style [css3Transform] = "matrix ("
+ (Cos * scale). toFixed (5) + "," + (Sin * scale). toFixed (5) + ","
+ (-Sin * scale). toFixed (5) + "," + (Cos * scale). toFixed (5) + ","
+ Math. round (x) + unit + "," + Math. round (y) + unit + ")";

Note that the calculated proportion may be a long decimal number, which may cause a problem during character spelling.
For example, if you run alert (0.0000001), you will get "1e-7". js will use this result to spell characters and get the wrong result.
Therefore, when splicing numbers and characters, the integer must be converted to an integer first, and the decimal number must be converted to toFixed.

[Zoom mode]

Ie does not support transform yet, but there is a zoom style that can achieve similar results.
Because the size changes after zoom, You need to modify the left and top to move to the correct position.

In addition to ie, webkit (chrome/safari) also supports zoom. However, the implementations of ie6/7, ie8, and webkit are not exactly the same.
Test the following code:

Copy codeThe Code is as follows: <style>
. Inner {width: 100px; height: 100px; position: absolute; background: # 0CF; zoom: 0.5; top: 50px; left: 50px ;}
. Inner div {width: 50px; height: 50px; position: absolute; left: 25px; background: # CCC ;}
</Style>
<Div style = "width: 150px; height: 150px; border: 1px solid #000; position: relative;">
<Div class = "inner" id = "t"> <div> test </div>
</Div>

The expected results are achieved in ie6/7, but the position displayed in webkit is incorrect.
The reason is that after zoom is used, the left and top of the element also scales, as long as it is recalculated in proportion.
As in the above example, you only need to change left and top to 50/0. 5, that is, 100 is correct.

Ie8 is more troublesome. The content is scaled by zoom, but left and top are still the original size.
This problem has plagued us for a long time. We finally found that we can solve this problem by positioning by percentage. This is the reason why left and top are used for image loading.
For example, in the example, modify left and top, and change left of div to 25%.
I also saw a problem in ie8. After zoom, the content is reduced, but the size of the container and internal elements is not changed. Fortunately, this will not affect the image display, left and top are also used for positioning, so as to avoid trouble.
Also, if the size of the zoom element is set in percentage, the element size will not be scaled according to the zoom.

Pay attention to one problem during computing. As mentioned above, in webkit and ie8, left and top, both must be divided by scale. When the scale is close to 0 to a certain extent, the result is Infinity ).
An error occurs when using Infinity for computation. You need to correct this problem:

Left = Math. min (MAX, Math. max (-MAX, left) | 0;
Top = Math. min (MAX, Math. max (-MAX, top) | 0;

MAX is Number. MAX_VALUE (the maximum Number that js can express ).

[Base mode]

The base mode compatible with all browsers also uses the traditional method, that is, to calculate and set the size and position of each image based on the scaling ratio.
For each display, the settings are calculated one by one based on the pictures in the calendar layer.
Calculate the original position and size of the image. During the first calculation, the data is saved in the _ original attribute:

Var original = img. _ original = img. _ original | {
Width: img. offsetWidth, height: img. offsetHeight,
Left: img. offsetLeft, top: img. offsetTop
};

You only need to scale the size according to the scale. In addition to calculating the relative layer scaling, you must add the relative container displacement. This is the same as the zoom mode calculation.
After understanding the layer transformation method, it is not difficult to understand this.

[ZIndex]

In addition to scaling and positioning, the depth also needs reasonable front-end and back-cover.
ZIndex is required for front-end and back-to-back masking. You can set it on an image or layer.
First, the simplest method is to set on the layer:

Copy codeThe Code is as follows: <style>
Div, img {width: 200px; height: 200px; position: absolute; left: 0; top: 0 ;}
Img {width: 150px; height: 150px ;}
</Style>
<Div style = "z-index: 300;">

</Div>
<Div style = "z-index: 100;">

</Div>

You can set the general 3D effect in this way.
However, when you click test, the content that can be triggered before ff and webkit cannot be triggered, While ie and opera can both be triggered.
Ps: If img is changed to div, the elements behind ie and opera cannot be triggered. The reason is unclear.
To trigger an image event like 3DRoom, you cannot set zIndex at the layer.
You can also set it on the image:

Copy codeThe Code is as follows: <style>
Div, img {width: 200px; height: 200px; position: absolute; left: 0; top: 0 ;}
Img {width: 150px; height: 150px ;}
</Style>
<Div>

</Div>
<Div>

</Div>

In this way, images can be normally triggered in all browsers, but the effect of stack-based ie6/7 is invalid. It seems that ie6/7 can only use zIndex at the layer.
Another problem is that if you add the transform effect to the div:
Div {-moz-transform: scale (1);-webkit-transform: scale (1);-o-transform: scale (1 );}
Then the zIndex on the image will expire, and the css3 mode can only set zIndex at the layer.

Summary:
In css3 mode, zIndex must be set at the layer, but the image cannot trigger events.
In zoom and base modes, zIndex should be set in the image, but in ie6/7, zIndex must be set at the layer.
In this way, at least in the base mode cascade and image trigger events are normal.

[MsInterpolationMode]

At the beginning, the effect will be very stuck in ie8, but this 3DRoom won't be stuck, and it is found that the-ms-interpolation-mode is used.
I have read this article in aoao, but I didn't expect it to be used here.

MsInterpolationMode is introduced in MSDN:
Gets or sets the interpolation (resampling) method used to stretch images.
That is, the interpolation (re-sampling) method used to draw an image is obtained or set.
It has two values:
Nearest-neighbor: uses the nearest neighbor interpolation mode.
Bicubic: uses a high-quality double-cubic Interpolation mode.
These terms are more professional. We only need to know that the use of nearest-neighbor is highly efficient, but the effect is poor, while the effectiveness of bicubic is low.
The Program sets it as nearest-neighbor to improve efficiency, so it won't be stuck in ie8.

[Drag direction conversion/scroll wheel depth Transformation]

The program extends the drag visual transformation and wheel depth transformation.
The drag and scroll operations are similar to the previous one. Here, the drag operation implements the direction conversion and the scroll wheel implements the depth transformation.
Moving is implemented by modifying the _ x and _ y attributes, and zooming is implemented by modifying _ z.
After modifying the attributes, call the show method to display the results.

Tips

[3DRoom]

In the 3DRoom effect, the css3 mode is unavailable because the image triggering event is implemented.
As mentioned above, the size of the zoom element in ie8 will not change, resulting in a trigger Range Error. Therefore, the zoom mode is not required.
Using the base mode won't be a problem.

When you click an image, the image will be moved to the image. After you click the image, modify _ x/_ y/_ z according to the 3D parameters:

Img. onclick = function (){
I3D. _ z =-options. z | 0;
I3D. _ x =-options. x | 0;
I3D. _ y = options. y | 0;
I3D. show ();
}

A border is displayed when the image is mouseover. To prevent the image from being displaced after the border is added, a "-1px" margin is added and removed when the image is mouseout.
Here, there is still a gap between the 3DRoom and the reference results. This article focuses on the implementation and Research of 3D effects.

[Mode Selection]

The css3 mode is stable, and most browsers support it except ie.
The zoom mode has poor compatibility, but ie supports it.
The base is the slowest, but has good compatibility and no bugs.
Generally, the css3 mode should be used first, followed by zoom and base. However, in the case of 3DRoom, the actual selection is required.
During the design, ie intends to use the Matrix filter. However, some problems are found during development and the efficiency is too low, so I will not consider it.

Instructions for use

During instantiation, containers must be included as parameters:

Var i3D = new Image3D (container, options );

Then, call the i3D method to add an image:

I3D. add (src, options );

Optional parameters are used to set the default attributes of the system, including:
Attribute: Default Value // description
Mode: "css3 | zoom | base", // mode
X: 0, // horizontal offset value
Y: 0, // vertical offset value
Z: 0, // depth Offset Value
R: 0, // rotation angle (supported by css3)
FixedFar: false, // do you want to fix the issue?
GetScale: function (z) {return 1-z/1000;}, // obtain the Ratio Method
OnError: function (err) {}// executed when an error occurs

The optional parameters of the add method are described in image loading.

The following methods are also provided:
Add: add an image;
Show: Display effect;
Reset: reset the default status;
Dispose: destroys a program.

After adding the drag direction transform or wheel depth transformation extension, you can define the transformation range by setting relevant parameters.

Packaging http://demo.jb51.net/js/Image3D/index.htm
Demo address/201010/yuanma/Image3D.rar

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.