Это должно решить проблему липкости.
Я видел по вашему демонстрационному сайту, что когда мышь находится над внутренним фреймом, у нас возникает проблема с липкостью.Это связано с тем, что внутренний iframe не накапливает событие до корневого элемента документа, который обрабатывает событие mouseDove в zDrag.
Я решил эту проблему, добавив оверлей div (невидимый, но есть), который занимает всю областькорневой документ, тем самым эффективно предотвращая перемещение мышью по внутреннему фрейму.И поскольку этот оверлейный элемент div является прямым потомком нашего корневого элемента документа, он корректно отображает событие mousemove.
Изменения включают в себя дополнительный метод получения высоты документа (от http://james.padolsey.com/javascript/get-document-height-cross-browser/), и изменения наметод zDrag для добавления / отображения / скрытия элемента наложения.
function getDocHeight() {
var D = document;
return Math.max(
Math.max(D.body.scrollHeight, D.documentElement.scrollHeight),
Math.max(D.body.offsetHeight, D.documentElement.offsetHeight),
Math.max(D.body.clientHeight, D.documentElement.clientHeight)
);
}
function zDrag(elementToDrag, event) {
var scroll = getScrollOffsets();
// create/show overlay - over the inner iframe and everything else
var div = document.getElementById('overlay');
if(div==null) {
div = document.createElement('div');
div.id = 'overlay';
div.style.position = 'absolute';
div.style.left = '0px';
div.style.top = '0px';
div.style.width = '100%';
div.style.height = getDocHeight()+'px';
div.style.zIndex = 99999;
div.style.cursor = 'move';
var bodyTag = document.getElementsByTagName("body")[0];
bodyTag.appendChild(div);
}
else {
div.style.display = 'block';
}
var startX = event.clientX + scroll.x;
var startY = event.clientY + scroll.y;
var origX = elementToDrag.offsetLeft;
var origY = elementToDrag.offsetTop;
var deltaX = startX - origX;
var deltaY = startY - origY;
if (document.addEventListener) {
document.addEventListener("mousemove", moveHandler, true);
document.addEventListener("mouseup", upHandler, true);
}
else if (document.attachEvent) {
/*elementToDrag.setCapture();
elementToDrag.attachEvent("onmousemove", moveHandler);
elementToDrag.attachEvent("onmouseup", upHandler);
elementToDrag.attachEvent("onlosecapture", upHandler);*/
// attach the events to the document element, to ensure we dont 'miss' any move events.
document.setCapture();
document.attachEvent("onmousemove", moveHandler);
document.attachEvent("onmouseup", upHandler);
document.attachEvent("onlosecapture", upHandler);
}
if (event.stopPropagation) event.stopPropagation();
else event.cancelBubble = true;
if (event.preventDefault) event.preventDefault();
else event.returnValue = false;
function moveHandler(e) {
if (!e) e = window.event;
var scroll = getScrollOffsets();
elementToDrag.style.left = getLeft(e.clientX + scroll.x - deltaX,true) + "px";
elementToDrag.style.top = getTop(e.clientY + scroll.y - deltaY,true) + "px";
if (e.stopPropagation) e.stopPropagation();
else e.cancelBubble = true;
};
function upHandler(e) {
// dragging is over. hide the overlay.
document.getElementById('overlay').style.display = 'none';
if (!e) e = window.event;
if (document.removeEventListener) {
document.removeEventListener("mouseup", upHandler, true);
document.removeEventListener("mousemove", moveHandler, true);
}
else if (document.detachEvent) {
/*elementToDrag.detachEvent("onlosecapture", upHandler);
elementToDrag.detachEvent("onmouseup", upHandler);
elementToDrag.detachEvent("onmousemove", moveHandler);
elementToDrag.releaseCapture();*/
document.detachEvent("onlosecapture", upHandler);
document.detachEvent("onmouseup", upHandler);
document.detachEvent("onmousemove", moveHandler);
document.releaseCapture();
}
if (e.stopPropagation) e.stopPropagation();
else e.cancelBubble = true;
};
}
EDIT - для ограничения перетаскивания внутри области просмотра
Теперь он будет ограничивать перетаскивание довнутри окна просмотра (т. е. внутренней ширины и высоты окна браузера). Изменения включают в себя: a) дополнительную функцию кросс-браузера, позволяющую получить внутреннюю ширину и высоту окна (от http://www.javascripter.net/faq/browserw.htm) и b), изменения метода moveHandler () (внутри метода zDrag) для проверки и применения ограничений.
function getWindowSize() {
var winW = 630, winH = 460;
if (document.body && document.body.offsetWidth) {
winW = document.body.offsetWidth;
winH = document.body.offsetHeight;
}
if (document.compatMode=='CSS1Compat' && document.documentElement && document.documentElement.offsetWidth ) {
winW = document.documentElement.offsetWidth;
winH = document.documentElement.offsetHeight;
}
if (window.innerWidth && window.innerHeight) {
winW = window.innerWidth;
winH = window.innerHeight;
}
return {width: winW, height: winH};
}
А внутри zDrag () замените текущий moveHandler на:
function moveHandler(e) {
if (!e) e = window.event;
var scroll = getScrollOffsets();
var newLeft = getLeft(e.clientX + scroll.x - deltaX,true);
if(newLeft + elementToDrag.offsetWidth > winDim.width) {
newLeft = winDim.width - elementToDrag.offsetWidth;
}
elementToDrag.style.left = newLeft + "px";
var newTop = getTop(e.clientY + scroll.y - deltaY,true);
if(newTop + elementToDrag.offsetHeight > winDim.height) {
newTop = winDim.height - elementToDrag.offsetHeight;
}
elementToDrag.style.top = newTop + "px";
if (e.stopPropagation) e.stopPropagation();
else e.cancelBubble = true;
};
EDIT - переменная winDim
winDim - это переменная, в которой хранятся размеры области просмотра.Он используется в обработчике перемещения, чтобы проверить, находится ли наш движимый объект в области просмотра.Я держал его снаружи, чтобы избежать пересчета размеров окна при каждом событии перемещения, которое может ухудшить производительность.
var winDim = null;
function zDrag(...) {
if(winDim == null) winDim = getWindowSize
// ... rest of the code in zDrag ...
}