Complete JavaScript comments on the drag-and-drop effect of google's personalized homepage [to] by Tin
Source: http://www.blogjava.net/iamtin/archive/2006/04/27/43668.html
Code: http://www.blogjava.net/Files/iamtin/google_drag.rar
The Code is as follows:
// Tool class, which uses the Util namespace for convenient management
Var Util = new Object ();
// Obtain the UserAgent and browser information in the http header
Util. getUserAgent = navigator. userAgent;
// Whether it is the core Browser of Gecko, such as ILA and Firefox
Util. isGecko = Util. getUserAgent. indexOf ("Gecko ")! =-1;
// Whether it is Opera
Util. isOpera = Util. getUserAgent. indexOf ("Opera ")! =-1;
// Obtain the offset information of an element, which is the absolute coordinate relative to the padding of the Body.
// If the following parameter is true, offsetLeft is obtained. If the parameter is false, offsetTop is obtained.
// For the definition of offset, style, client and other coordinates, see this post of dindin: http://www.jroller.com/page/dindin? Anchor = pro_javascript_12
Util. getOffset = function (el, isLeft ){
Var retValue = 0;
While (el! = Null ){
RetValue + = el ["offset" + (isLeft? "Left": "Top")];
El = el. offsetParent;
}
Return retValue;
};
// Bind a function (funcName In the parameter is the name of this function) to an element and run it in the context of this element, which is actually an inheritance, please refer to some google articles.
Util. bindFunction = function (el, fucName ){
Return function (){
Return el [fucName]. apply (el, arguments );
};
};
// Recalculate the coordinates of all the elements that can be dragged, and recalculate the height of the elements that can be dragged under the same column to obtain new coordinates, so as to prevent stacking.
// The calculated coordinates are recorded in the pagePosLeft and pagePosTop attributes.
Util. re_calcOff = function (el ){
For (var I = 0; I <Util. dragArray. length; I ++ ){
Var ele = Util. dragArray [I];
Ele. elm. pagePosLeft = Util. getOffset (ele. elm, true );
Ele. elm. pagePosTop = Util. getOffset (ele. elm, false );
}
Var nextSib = el. elm. nextSibling;
While (nextSib ){
NextSib. pagePosTop-= el. elm. offsetHeight;
NextSib = nextSib. nextSibling;
}
};
// Hide the table in the middle of Google Ig, that is, the drag container. In combination with show, it is usually used for Refresh, solving some browser quirks.
Util. hide = function (){
Util. rootElement. style. display = "none ";
};
// Display the table in the center of Google Ig. The explanation is the same as above.
Util. show = function (){
Util. rootElement. style. display = "";
};
// The placeholder dotted box displayed when moving
GhostElement = null;
// Obtain the dotted box and dynamically generate it through dom
GetGhostElement = function (){
If (! GhostElement ){
GhostElement = document. createElement ("DIV ");
GhostElement. className = "modbox ";
GhostElement. backgroundColor = "";
GhostElement. style. border = "2px dashed # aaa ";
GhostElement. innerHTML = "";
}
Return ghostElement;
};
// Initialize the Element function that can be dragged. I have removed the Element that is irrelevant to the drag operation.
Function draggable (el ){
// Common start-drag Function
This. _ dragStart = start_Drag;
// Common drag-and-drop Functions
This. _ drag = when_Drag;
// Common drag-and-drop Function
This. _ dragEnd = end_Drag;
// This function is mainly used for dom processing after dragging.
This. _ afterDrag = after_Drag;
// Whether it is being dragged. Of course it is not being dragged at the beginning
This. isDragging = false;
// Register the this pointer of this Element in the elm variable, which is a common method to call functions other than the context.
This. elm = el;
// Trigger the drag Element. Here is the p that displays the title on the p.
This. header = document. getElementById (el. id + "_ h ");
// Drag different elements with iframe. Check and record them here.
This. hasIFrame = this. elm. getElementsByTagName ("IFRAME"). length> 0;
// If the header is found, bind the drag-related event
If (this. header ){
// Cursor of the fork when dragging
This. header. style. cursor = "move ";
// Bind the function to this of the header and element. Refer to the description of the function.
Drag. init (this. header, this. elm );
// The following three statements bind the written three functions to the three function hooks of this elemnt, which realizes that the element inherits the drag-and-drop functions from draggable.
This. elm. onDragStart = Util. bindFunction (this, "_ dragStart ");
This. elm. onDrag = Util. bindFunction (this, "_ drag ");
This. elm. onDragEnd = Util. bindFunction (this, "_ dragEnd ");
}
};
// Below are the four functions used in draggable.
// Common start-drag Function
Function start_Drag (){
// Reset the coordinates to achieve the effect of filling your position immediately after dragging
Util. re_calcOff (this );
// Record the original neighbor node to compare whether it is moved to a new location
This. origNextSibling = this. elm. nextSibling;
// Obtain the gray dotted box when moving
Var _ ghostElement = getGhostElement ();
// Obtain the height of the Moving Object
Var offH = this. elm. offsetHeight;
If (Util. isGecko ){
// Modify the geek of the gecko Engine
OffH-= parseInt (_ ghostElement. style. borderTopWidth) * 2;
}
// Obtain the width of the Moving Object
Var offW = this. elm. offsetWidth;
// Obtain the coordinates of left and top
Var offLeft = Util. getOffset (this. elm, true );
Var offTop = Util. getOffset (this. elm, false );
// Prevent flickering and hide
Util. hide ();
// Record your own width in the style attribute
This. elm. style. width = offW + "px ";
// Set the gray box to be as high as the object being dragged, and compare the image
_ GhostElement. style. height = offH + "px ";
// Place the gray box in the original position of the object.
This. elm. parentNode. insertBefore (_ ghostElement, this. elm. nextSibling );
// Because the dragged object must be extracted from the original box model, set position to absolute. For details, refer to css layout.
This. elm. style. position = "absolute ";
// Set zIndex to keep it at the top layer. Of course, zIndex = 100 is very front-end. If zIndex> 100 is on the page, then ......
This. elm. style. zIndex = 100;
// Since position = absolute, left and top are used to locate absolute coordinates. This is the role of coordinates previously calculated. We do not want this model to run in disorder. We need to move it from the start point.
This. elm. style. left = offLeft + "px ";
This. elm. style. top = offTop + "px ";
// After the coordinates are set, they can be displayed, so they won't flash.
Util. show ();
// There is an ig_d.G here. I don't know what to do, but I can use it if I don't know what to do. I'm sorry.
// You have not started dragging. Here is a mark.
This. isDragging = false;
Return false;
};
// The corresponding function during dragging. The coordinates clientX and clientY of the mouse are passed in because it is bound to the move event of the mouse.
Function when_Drag (clientX, clientY ){
// At the beginning, the layer is transparent and marked as being dragged.
If (! This. isDragging ){
This. elm. style. filter = "alpha (opacity = 70 )";
This. elm. style. opacity = 0.7;
This. isDragging = true;
}
// The new column to be dragged (which can also be the original one)
Var found = null;
// The maximum distance, which may prevent overflow or any bugs
Var max_distance = 100000000;
// Traverse all the drag-and-drop elements to find the drag-and-drop element closest to the current mouse coordinate so that it can be inserted later
For (var I = 0; I <Util. dragArray. length; I ++ ){
Var ele = Util. dragArray [I];
// Calculate the distance from the mouse to the element traversed by using the hook Theorem
Var distance = Math. sqrt (Math. pow (clientX-ele. elm. pagePosLeft, 2) + Math. pow (clientY-ele. elm. pagePosTop, 2 ));
// You are floating, so do not calculate your own
If (ele = this ){
Continue;
}
// Continue the loop if the calculation fails
If (isNaN (distance )){
Continue;
}
// If it is smaller, record the distance and use it as the found
If (distance <max_distance ){
Max_distance = distance;
Found = ele;
}
}
// Prepare the gray box to settle
Var _ ghostElement = getGhostElement ();
// If another foothold is found
If (found! = Null & _ ghostElement. nextSibling! = Found. elm ){
// Locate the foothold and insert the gray box first. This is the special effect of the gray box we see. It is a bit like adsorption. Haha
Found. elm. parentNode. insertBefore (_ ghostElement, found. elm );
If (Util. isOpera ){
// The actual problem of Opera is that changes can only be refreshed after being hidden/displayed.
Document. body. style. display = "none ";
Document. body. style. display = "";
}
}
};
// Drag and drop
Function end_Drag (){
// After dragging, execute the following hook and execute after_Drag (). If the layout changes, record it to the remote server and save the new layout order after dragging.
If (this. _ afterDrag ()){
// Remote call to save the change
}
Return true;
};
// Execution hook after dragging
Function after_Drag (){
Var returnValue = false;
// Prevent flickering
Util. hide ();
// Remove position = absolute and related styles when dragging
This. elm. style. position = "";
This. elm. style. width = "";
This. elm. style. zIndex = "";
This. elm. style. filter = "";
This. elm. style. opacity = "";
// Get the gray box
Var ele = getGhostElement ();
// If the current neighbor is not the original neighbor
If (ele. nextSibling! = This. origNextSibling ){
// Insert the dragged node to the front of the gray box.
Ele. parentNode. insertBefore (this. elm, ele. nextSibling );
// Indicates that a new place has been dragged.
ReturnValue = true;
}
// Remove the gray box. This is the end of the lifecycle of the gray box.
Ele. parentNode. removeChild (ele );
// After modification, display
Util. show ();
If (Util. isOpera ){
// The actual problem of Opera is that changes can only be refreshed after being hidden/displayed.
Document. body. style. display = "none ";
Document. body. style. display = "";
}
Return returnValue;
};
// The original form of the drag-and-drop Element is used to bind the event to each hook. This is common in some cities, and netvibes is basically the same.
// This part of the recommendation to see this dindin, will also help understand, http://www.jroller.com/page/dindin? Anchor = pro_javascript_12
Var Drag = {
// Reference this element. Only one Element can be dragged at a time.
Obj: null,
// Element is the reference of the dragged object, and elementHeader is the area where the mouse can drag
Init: function (elementHeader, element ){
// Bind start to the onmousedown event and press the mouse to trigger start.
ElementHeader. onmousedown = Drag. start;
// Save the element to the obj of the header to facilitate reference when the header is dragged.
ElementHeader. obj = element;
// Initialize absolute coordinates. It does not take any effect because it is not position = absolute, but it prevents parse errors when onDrag is followed.
If (isNaN (parseInt (element. style. left ))){
Element. style. left = "0px ";
}
If (isNaN (parseInt (element. style. top ))){
Element. style. top = "0px ";
}
// Initiate the above functions. After Drag. init is called, you can refer to the content in draggable.
Element. onDragStart = new Function ();
Element. onDragEnd = new Function ();
Element. onDrag = new Function ();
},
// Start the drag binding and bind it to the event where the mouse moves
Start: function (event ){
Var element = Drag. obj = this. obj;
// Solve the problem of different event models in different browsers
Event = Drag. fixE (event );
// Check whether the left button is clicked.
If (event. which! = 1 ){
// Does not work except the left button
Return true;
}
// Refer to the description of this function to hook up the start-drag hook.
Element. onDragStart ();
// Record the mouse coordinates
Element. lastMouseX = event. clientX;
Element. lastMouseY = event. clientY;
// Bind the Global event to the dragged element.
Document. onmouseup = Drag. end;
Document. onmousemove = Drag. drag;
Return false;
},
// The function in which the Element is being dragged
Drag: function (event ){
// Solve the problem of different event models in different browsers
Event = Drag. fixE (event );
// Check whether the left button is clicked.
If (event. which = 0 ){
// Does not work except the left button
Return Drag. end ();
}
// The Element being dragged
Var element = Drag. obj;
// Mouse coordinates
Var _ clientX = event. clientY;
Var _ clientY = event. clientX;
// If the mouse does not move, nothing will be done.
If (element. lastMouseX ==_clienty & element. lastMouseY ==_clientx ){
Return false;
}
// Coordinates of the Element
Var _ lastX = parseInt (element. style. top );
Var _ lastY = parseInt (element. style. left );
// New coordinates
Var newX, newY;
// Calculate the new coordinates: the original coordinates + The Value Difference Between the mouse movement
NewX = _ lastY + _ clientY-element. lastMouseX;
NewY = _ lastX + _ clientX-element. lastMouseY;
// Modify the display coordinate of the element
Element. style. left = newX + "px ";
Element. style. top = newY + "px ";
// Record the current coordinates of the element for the next movement
Element. lastMouseX = _ clientY;
Element. lastMouseY = _ clientX;
// Refer to the explanation of this function to hook up the Drag.
Element. onDrag (newX, newY );
Return false;
},
// The function whose Element is being released. Stop dragging.
End: function (event ){
// Solve the problem of different event models in different browsers
Event = Drag. fixE (event );
// Unbind Global events
Document. onmousemove = null;
Document. onmouseup = null;
// Record the onDragEnd hook first to remove the obj
Var _ onDragEndFuc = Drag. obj. onDragEnd ();
// After dragging, clear obj
Drag. obj = null;
Return _ onDragEndFuc;
},
// Solve the problem of different event models in different browsers
FixE: function (ig _){
If (typeof ig _ = "undefined "){
Ig _ = window. event;
}
If (typeof ig _. layerX = "undefined "){
Ig _. layerX = ig _. offsetX;
}
If (typeof ig _. layerY = "undefined "){
Ig _. layerY = ig _. offsetY;
}
If (typeof ig _. which = "undefined "){
Ig _. which = ig _. button;
}
Return ig _;
}
};
// The following is the initialization function. Let's see how these items are called.
Var _ IG_initDrag = function (el ){
// The column container is the tbody of the table layout in google, which is used by netvibes.
Util. rootElement = el;
// The row of the tbody
Util. _ rows = Util. rootElement. tBodies [0]. rows [0];
// Column. google has three columns, but more
Util. column = Util. _ rows. cells;
// Used to access drag-and-drop objects
Util. dragArray = new Array ();
Var counter = 0;
For (var I = 0; I <Util. column. length; I ++ ){
// Search all columns
Var ele = Util. column [I];
For (var j = 0; j <ele. childNodes. length; j ++ ){
// Search all elements in each column
Var ele1 = ele. childNodes [j];
// Initialize p as a draggable object.
If (ele1.tagName = "DIV "){
Util. dragArray [counter] = new draggable (ele1 );
Counter ++;
}
}
}
};
// The id of the part that can be dragged on the google page is "t_1"
// Mount the file to onload. The file is loaded and executed. However, google does not actually use onload.
// It is written at the bottom of the page. It is similar. It may be a strange thing to write directly on the page, or it may be compatibility considerations.
// Add the following two commented-out codes to a google ig page you downloaded, delete all the other scripts in it, and drag and drop the js, haha
// _ Table = document. getElementById ("t_1 ");
// Window. onload = _ IG_initDrag (_ table );
// Actually, understanding the code is helpful for learning javascript and I hope it will help you.