/* * drag.js - click & drag DOM elements * * originally based on Youngpup's dom-drag.js, www.youngpup.net */ var Drag = { BIG_Z_INDEX : 10000, group : null, isDragging : false, makeDraggable : function(group) { group.handle = group; group.handle.group = group; group.minX = null; group.minY = null; group.maxX = null; group.maxY = null; group.threshold = 0; group.thresholdY = 0; group.thresholdX = 0; group.onDragStart = new Function(); group.onDragEnd = new Function(); group.onDrag = new Function(); // TODO: use element.prototype.myFunc group.setDragHandle = Drag.setDragHandle; group.setDragThreshold = Drag.setDragThreshold; group.setDragThresholdX = Drag.setDragThresholdX; group.setDragThresholdY = Drag.setDragThresholdY; group.constrain = Drag.constrain; group.constrainVertical = Drag.constrainVertical; group.constrainHorizontal = Drag.constrainHorizontal; group.onmousedown = Drag.onMouseDown; }, constrainVertical : function() { var nwOffset = Coordinates.northwestOffset(this, true); this.minX = nwOffset.x; this.maxX = nwOffset.x; }, constrainHorizontal : function() { var nwOffset = Coordinates.northwestOffset(this, true); this.minY = nwOffset.y; this.maxY = nwOffset.y; }, constrain : function(nwPosition, sePosition) { this.minX = nwPosition.x; this.minY = nwPosition.y; this.maxX = sePosition.x; this.maxY = sePosition.y; }, setDragHandle : function(handle) { if (handle && handle != null) this.handle = handle; else this.handle = this; this.handle.group = this; this.onmousedown = null; this.handle.onmousedown = Drag.onMouseDown; }, setDragThreshold : function(threshold) { if (isNaN(parseInt(threshold))) return; this.threshold = threshold; }, setDragThresholdX : function(threshold) { if (isNaN(parseInt(threshold))) return; this.thresholdX = threshold; }, setDragThresholdY : function(threshold) { if (isNaN(parseInt(threshold))) return; this.thresholdY = threshold; }, onMouseDown : function(event) { event = Drag.fixEvent(event); Drag.group = this.group; var group = this.group; var mouse = event.windowCoordinate; var nwOffset = Coordinates.northwestOffset(group, true); var nwPosition = Coordinates.northwestPosition(group); var sePosition = Coordinates.southeastPosition(group); var seOffset = Coordinates.southeastOffset(group, true); group.originalOpacity = group.style.opacity; group.originalZIndex = group.style.zIndex; group.initialWindowCoordinate = mouse; // TODO: need a better name, but don't yet understand how it // participates in the magic while dragging group.dragCoordinate = mouse; Drag.showStatus(mouse, nwPosition, sePosition, nwOffset, seOffset); group.onDragStart(nwPosition, sePosition, nwOffset, seOffset); // TODO: need better constraint API if (group.minX != null) group.minMouseX = mouse.x - nwPosition.x + group.minX - nwOffset.x; if (group.maxX != null) group.maxMouseX = group.minMouseX + group.maxX - group.minX; if (group.minY != null) group.minMouseY = mouse.y - nwPosition.y + group.minY - nwOffset.y; if (group.maxY != null) group.maxMouseY = group.minMouseY + group.maxY - group.minY; group.mouseMin = new Coordinate(group.minMouseX, group.minMouseY); group.mouseMax = new Coordinate(group.maxMouseX, group.maxMouseY); document.onmousemove = Drag.onMouseMove; document.onmouseup = Drag.onMouseUp; return false; }, showStatus : function(mouse, nwPosition, sePosition, nwOffset, seOffset) { window.status = "mouse: " + mouse.toString() + " " + "NW pos: " + nwPosition.toString() + " " + "SE pos: " + sePosition.toString() + " " + "NW offset: " + nwOffset.toString() + " " + "SE offset: " + seOffset.toString(); }, onMouseMove : function(event) { event = Drag.fixEvent(event); var group = Drag.group; var mouse = event.windowCoordinate; var nwOffset = Coordinates.northwestOffset(group, true); var nwPosition = Coordinates.northwestPosition(group); var sePosition = Coordinates.southeastPosition(group); var seOffset = Coordinates.southeastOffset(group, true); Drag.showStatus(mouse, nwPosition, sePosition, nwOffset, seOffset); if (!Drag.isDragging) { if (group.threshold > 0) { var distance = group.initialWindowCoordinate.distance( mouse); if (distance < group.threshold) return true; } else if (group.thresholdY > 0) { var deltaY = Math.abs(group.initialWindowCoordinate.y - mouse.y); if (deltaY < group.thresholdY) return true; } else if (group.thresholdX > 0) { var deltaX = Math.abs(group.initialWindowCoordinate.x - mouse.x); if (deltaX < group.thresholdX) return true; } Drag.isDragging = true; group.style["zIndex"] = Drag.BIG_Z_INDEX; group.style["opacity"] = 0.75; } // TODO: need better constraint API var adjusted = mouse.constrain(group.mouseMin, group.mouseMax); nwPosition = nwPosition.plus(adjusted.minus(group.dragCoordinate)); nwPosition.reposition(group); group.dragCoordinate = adjusted; // once dragging has started, the position of the group // relative to the mouse should stay fixed. They can get out // of sync if the DOM is manipulated while dragging, so we // correct the error here // // TODO: what we really want to do is find the offset from // our corner to the mouse coordinate and adjust to keep it // the same var offsetBefore = Coordinates.northwestOffset(group); group.onDrag(nwPosition, sePosition, nwOffset, seOffset); var offsetAfter = Coordinates.northwestOffset(group); if (!offsetBefore.equals(offsetAfter)) { var errorDelta = offsetBefore.minus(offsetAfter); nwPosition = Coordinates.northwestPosition(group).plus(errorDelta); nwPosition.reposition(group); } return false; }, onMouseUp : function(event) { event = Drag.fixEvent(event); var group = Drag.group; var mouse = event.windowCoordinate; var nwOffset = Coordinates.northwestOffset(group, true); var nwPosition = Coordinates.northwestPosition(group); var sePosition = Coordinates.southeastPosition(group); var seOffset = Coordinates.southeastOffset(group, true); document.onmousemove = null; document.onmouseup = null; group.onDragEnd(nwPosition, sePosition, nwOffset, seOffset); if (Drag.isDragging) { // restoring zIndex before opacity avoids visual flicker in Firefox group.style["zIndex"] = group.originalZIndex; group.style["opacity"] = group.originalOpacity; } Drag.group = null; Drag.isDragging = false; return false; }, fixEvent : function(event) { if (typeof event == 'undefined') event = window.event; Coordinates.fixEvent(event); return event; } };