Author: Tin
Source: http://www.blogjava.net/iamtin/archive/2006/04/27/43668.html
Code: http://www.blogjava.net/Files/iamtin/ google_drag.rar
// Tool class, using Util’s namespace for easy management
var Util = new Object();
// Get the UserAgent and browser information in the http header
Util. getUserAgent = navigator.userAgent;
// Whether it is the core Browser of Gecko, such as Mozila, Firefox
Util.isGecko = Util.getUserAgent.indexOf( " Gecko " ) != - 1 ;
// Whether Is Opera
Util.isOpera = Util.getUserAgent.indexOf( " Opera " ) != - 1 ;
// Get the offset information of an element, which is actually the absolute coordinate within the padding relative to the Body
// If the latter parameter is true, it will get offsetLeft, if it is false, it will be offsetTop
// For the definition of offset, style, client and other coordinates, please refer to 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; fuction name) is bound to an element and runs in the context of this element. It is actually a kind of inheritance. You can google some articles to see this.
Util.bindFunction = function (el, fucName) {
return function () {
return el[fucName].apply(el, arguments);
};
};
// Recalculate the coordinates of all draggable elements for the same The draggable layers below the column recalculate their heights to obtain new coordinates to prevent overlapping
// The calculated coordinates are recorded in the two attributes pagePosLeft and pagePosTop
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 (nextS ib ) {
nextSib.pagePosTop -= el.elm.offsetHeight;
nextSib = nextSib.nextSibling;
}
};
// Hide the table in the middle of Google Ig, also It is a drag-and-drop container. It is usually used for refreshing when used with show to solve some browser quirks.
Util.hide = function () {
Util.rootElement.style.display = " none " ;
};
//Show the table in the middle of Google Ig, the explanation is the same as above
Util.show = Function () {
Util.rootElement.style.display = "" ;
};
// Placeholder dotted box displayed when moving
ghostElement = null ;
// Get this 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;
};
// Function to initialize the draggable Element I removed the ones that have nothing to do with dragging
function draggable(el) {
// Common dragging function
this ._dragStart = start_Drag; 🎜> this ._dragEnd = when_Drag;
// Common drag-end 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 was not dragged at the beginning
this .isDragging = false;
// Register the this pointer of this Element in the elm variable , convenient for calling your own functions outside your own context, a very common method
this .elm = el;
// The Element that triggers dragging, here is the div that displays the title on this div
this .header = document.getElementById(el.id " _h " );
// Dragging and dropping of elements with iframes is different, check it here and record it
this .hasIFrame = this .elm.getElementsByTagName( " IFRAME " ).length > 0 ;
// If the header is found, bind the drag-related event
if (this .header) {
// The fork mouse pointer when dragging
this .header.style.cursor = " move " ;
// Bind the function to this of header and element, refer to the description of that function
Drag.init(this .header, this .elm);
// The following three statements bind the three written functions to the three function hooks of this elementnt, which also realizes that element inherits the draggable function from draggable Util.bindFunction( this , " _dragStart " );
this .elm.onDrag = Util.bindFunction( this , " _drag " );
this .elm.onDragEnd = Util.bindFunction( this , " _dragEnd " ) ;
}
};
// The following are the 4 functions used in draggable
// Common function to start dragging
function start_Drag() {
// Reset coordinates to achieve The effect that your position will be filled immediately after dragging
Util.re_calcOff( this );
// Record the original neighbor nodes to compare whether they have been moved to a new position
this .origNextSibling = this .elm.nextSibling;
// Get the gray dotted frame when moving
var _ghostElement = getGhostElement();
// Get the height of the moving object
var offH = this .elm.offsetHeight;
if (Util.isGecko) {
// Fix the quirks of the gecko engine
offH -= parseInt(_ghostElement.style.borderTopWidth) * 2;
}
// Get the width of the moving object
var offW = this .elm.offsetWidth;
// Get the coordinates of left and top
var offLeft = Util.getOffset(this .elm, true);
var offTop = Util.getOffset(this .elm, false);
// Prevent flickering, now hidden
Util.hide();
// Record your width in the style attribute " px " ;
// Put the gray box at the original position of this object
this .elm.parentNode.insertBefore(_ghostElement, this .elm.nextSibling);
// Because you want to drag it, you must The dragged object is extracted from the original box model, so set the position to absolute. You can refer to the knowledge of css layout for this.
This .elm.style.position = " absolute " ;
// Set zIndex so that it is at the front level. Of course, zIndex=100 means it is at the front. If there is zIndex>100 on the page, then...
this .elm.style.zIndex = 100 ;
// Since position=absolute, left and top achieve absolute coordinate positioning. This is the function of the previously calculated coordinates. To prevent this model from running around, start from Start moving where you started dragging
this .elm.style.left = offLeft " px " ;
this .elm.style.top = offTop " px " ;
// The coordinates are set, you can It is displayed, so it won’t flicker.
Util.show();
// There is an ig_d.G here. I don’t know what it is used for, but it can be used without it. Who knows, please tell me. , sorry
// Dragging hasn’t started yet, make a mark here
this .isDragging = false ;
return false ;
};
// Corresponding function during dragging , since it is bound to the mouse move event, the mouse coordinates clientX, clientY will be passed in.
function when_Drag(clientX, clientY) {
// Make the layer transparent when you first start dragging. 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 being dragged (of course it can be the original one)
var found = null ;
// The largest Distance, maybe to prevent overflow or some bug
var max_distance = 100000000;
// Traverse all draggable elements and find the draggable element closest to the current mouse coordinates for later insertion
for ( var i = 0 ; i < Util.dragArray.length; i ) {
var ele = Util.dragArray[i];
// Use the Pythagorean theorem to calculate the distance from the mouse to the traversed element Distance
var distance = Math.sqrt(Math.pow(clientX - ele.elm.pagePosLeft, 2) Math.pow(clientY - ele.elm.pagePosTop, 2));
// Already floated Got it , so do not calculate your own
(distance)) {
continue ;
}
// If it is smaller, record the distance and use it as found
if (distance < max_distance) {
max_distance = distance; Found = ele;
}
}
// Prepare for the gray frame to settle
var _ghostElement = getGhostElement();
// If another resting place is found
if (found != null && _ghostElement.nextSibling != found.elm ) {
// Find the foothold and insert the gray frame first. This is the special effect of the gray frame we see. _ghostElement, found.elm);
;
document.body. After dragging, execute the following hook and execute after_Drag(). If the layout changes, it will be recorded to the remote server and save the new layout order after you drag it.
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();
// Eliminate 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 gray box
var ele = getGhostElement();
// If the current neighbor is not the original neighbor
if (ele.nextSibling != this .origNextSibling ) {
// Insert the dragged node in front of the gray box
ele.parentNode.insertBefore( this .elm, ele.nextSibling);
// Indicate that the new node has been dragged Place
returnValue = true ;
}
// Remove the gray box, which should end the life cycle of this gray box
ele.parentNode.removeChild(ele);
/ /After the modification is completed, display Util.show ();
If (Util.isopera) {
// Opera's realistic problems, it must be hidden/displayed to refresh the change
documen.body. style.display = " none " ;
document.body.style.display = "" ;
}
return returnValue;
};
// The prototype of draggable Element is used to bind events to each hook. This part is relatively common in the market, and netvibes also implements it basically the same way.
// It is recommended to read this part from dindin. It will also help to understand, http://www.jroller.com/page/dindin/?anchor=pro_javascript_12
var Drag = {
// The reference to this element can only drag one Element at a time
obj: null ,
// element is a reference to the object being dragged, elementHeader is the area where the mouse can drag
init: function (elementHeader, element) {
// Bind start to onmousedown event, press the mouse to trigger start
elementHeader.onmousedown = Drag.start;
//Save the element in the obj of the header, so that it can be referenced when the header is dragged and dropped
elementHeader.obj = element;
// Initialize absolute coordinates, because it is not position=absolute, it will not play any role, but it will prevent parse errors later during onDrag. > " ;
}
initialize these members, the actual function is determined after Drag.init is called, you can refer to the contents in draggable . > element.onDragEnd = new Function();
element.onDrag = new Function();
},
// Start dragging and binding to the mouse movement event
start: function (event) {
var element = Drag.obj = this .obj;
// Solve the problem of different event models in different browsers
event = Drag.fixE(event);
/ Refer to the explanation of this function and hook up the hook to start dragging.
element.onDragStart();
// Record the mouse coordinates.
event .clientY;
// Bind the Global event to the dragged element
document.onmouseup = Drag.end;
document.onmousemove = Drag.drag;
re turn false ;
},
// The function of the Element being dragged
drag: function (event) {
// Solve the problem of different event models in different browsers
event = Drag.fixE(event);
// See if the left button is click
if (event.which == 0) {
// Except for the left button, it does not work
Return drag.end ();
}
// Element being dragged
var element = Drag.obj;
// Mouse coordinates
var _clientX = event.clientY;
var _clientY = event.clientX;
// Do nothing if the mouse is not moving Coordinates
var _lastX = parseInt(element.style.top);
var _lastY = parseInt(element.style.left);
// New coordinates
var newX , newY;
// Calculate new coordinates: the difference in mouse movement between the original coordinates
newX = _lastY _clientY - element.lastMouseX; // Modify the display coordinates of element
element.style.left = newX " px " ;
element.style.top = newY " px " ;
// Record the current coordinates of the element for the next move.
element.lastMouseX = _clientY ;
element.lastMouseY = _clientX;
// Refer to the explanation of this function to hook up the Drag
element.onDrag(newX, newY);
return false ;
},
// Function where Element is being released, stop dragging
end: function (event) {
// Solve the problem of different event models in different browsers
event = Drag.fixE( event);
// Unbind the Global event
document.onmousemove = null ;
document.onmouseup = null ;
// Record the onDragEnd hook first Sub, easy to remove obj
var _onDragEndFuc = Drag.obj.onDragEnd();
// After dragging, obj is cleared
Drag.obj = null ;
return _onDrag EndFuc;
},
// 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;
} off off
};
//The following is the initialization function, see how the above things are called
var _IG_initDrag = function (el) {
// column container, In Google, it is the tbody of the table layout, which is used by netvibes. .rows[ 0 ];
// Columns, Google has 3 columns, in fact there can be more
Util.column = Util._rows.cells;
// Used to access draggable objects
Util.dragArray = new Array();
var counter = 0;
for (var i = 0; i < Util.column.length; i ) {
// Search all column
var ele = Util.column[i];
for ( var j = 0 ; j < ele.childNodes.length; j ) {
// Search for each column all elements
var ele1 = ele.childNodes[j];
// If it is a div, initialize it as a draggable object
if (ele1.tagName == "DIV " ) {
Util.dragArray[ counter] = new draggable(ele1);
; id It is "t_1"
//Mounted to onload, and executed after loading. But in fact Google does not use onload.
// Instead, it is written at the bottom of the page, which is different but has the same effect. Maybe it is a quirk to write directly on the page, or it may be due to compatibility considerations.
// Please add the following two commented out codes to a google ig page you downloaded, delete all other scripts in it, and you can drag and drop this js, haha
// _table=document.getElementById("t_1");
// window.onload = _IG_initDrag(_table);
// In fact, understanding these codes is very helpful for learning javascript, I hope It can be helpful to everyone