Ответ 1
Ничего себе, идея рок.:) Я немного очистил ваш код и решил проблемы с инициализацией. Теперь он отлично работает для меня в Firefox и Chrome (даже если вы сказали, что это не должно).
Несколько примечаний:
- вам нужно захватить начальные позиции
top
иleft
во время инициализации (getBoundingClientRect) - сохраняйте ссылки, такие как
this.dragData
иelement.style
для краткости и быстрого выполнения -
dragData
может быть инициализирован как пустой объект. Это хорошо в javascript. Вы можете добавить свойства позже. -
options
должен быть условно инициализирован как пустой объект, так что вы можете использовать нулевые опции -
moved
иdragData.occuring
были абсолютно бесполезны из-за управления событиями -
preventDefault
необходим, чтобы не выбирать текст при перетаскивании - вы можете отслеживать
z-indexes
как активный элемент, всегда видимый
Удачи!
Код [Посмотрите в действии]
/**
* The draggable object.
*/
Draggable = function(targetElement, options) {
this.targetElement = targetElement;
// we can take zero options
options = options || {};
// Initialize drag data.
// @props: startX, startY, lastX, lastY,
// offsetX, offsetY, lastTime, occuring
this.dragData = {};
// Set the cursor style.
targetElement.style.cursor = 'move';
// The element to move.
var el = this.applyTo = options.applyTo || targetElement;
// Event methods for "mouse down", "up" and "move".
// Mouse up and move are binded to window.
// We can attach and deattach "move" and "up" events as needed.
var me = this;
targetElement.addEventListener('mousedown', function(event) {
me.onMouseDown.call(me, event);
}, false);
this.mouseUp = function(event) {
me.onMouseUp.call(me, event);
};
this.mouseMove = function(event) {
me.onMouseMove.call(me, event);
};
// initialize position, so it will
// be smooth even on the first drag
var position = el.getBoundingClientRect();
el.style.left = position.left + "px";
el.style.top = position.top + "px";
el.style.position = "absolute";
if (el.style.zIndex > Draggable.zindex)
Draggable.zindex = el.style.zIndex + 1;
};
Draggable.zindex = 0;
/**
* Sets the skew and saves the position
* @param {Number} skew
*/
Draggable.prototype.setSkew = function(skew) {
var data = this.dragData;
var style = this.applyTo.style;
// Set skew transformations.
data.skew = skew;
style.MozTransform = skew ? 'skew(' + skew + 'deg)' : '';
style.webkitTransform = skew ? 'skew(' + skew + 'deg)' : '';
// Save the new position.
style.left = (data.lastX + data.offsetX) + 'px';
style.top = (data.lastY + data.offsetY) + 'px';
}
/**
* The mouse down event.
* @param {Object} event
*/
Draggable.prototype.onMouseDown = function(event) {
var data = this.dragData;
// New drag event.
var style = this.applyTo.style;
data.startX = data.lastX = event.clientX;
data.startY = data.lastY = event.clientY;
data.offsetX = parseInt(style.left, 10) - event.clientX;
data.offsetY = parseInt(style.top, 10) - event.clientY;
style.zIndex = Draggable.zindex++;
data.lastTime = (new Date()).getTime();
// Mouse up and move events.
window.addEventListener('mousemove', this.mouseMove, false);
window.addEventListener('mouseup', this.mouseUp, false);
event.preventDefault(); // prevent text selection
};
/**
* The mouse movement event.
* @param {Object} event
*/
Draggable.prototype.onMouseMove = function(event) {
// He is dragging me now
var me = this;
var data = me.dragData;
var element = me.applyTo;
var clientX = event.clientX;
var clientY = event.clientY;
data.moving = true;
// The skew animation. :)
var skew = (data.lastX - clientX) * 1;
var limit = 25;
if (Math.abs(skew) > limit) {
skew = limit * (skew > 0 ? 1 : -1);
}
var style = element.style;
var left = parseInt(style.left, 10);
var top = parseInt(style.top, 10);
var transform =
'translateX(' + (clientX + data.offsetX - left) + 'px)' +
'translateY(' + (clientY + data.offsetY - top) + 'px)' +
'skew(' + skew + 'deg)';
style.MozTransform = transform;
style.webkitTransform = transform;
data.lastX = clientX;
data.lastY = clientY;
data.lastTime = (new Date()).getTime();
// here is the cooldown part in order
// not to stay in disorted state
var pre = skew > 0 ? 1 : -1;
clearInterval(data.timer);
data.timer = setInterval(function() {
var skew = data.skew - (pre * 10);
skew = pre * skew < 0 ? 0 : skew;
me.setSkew(skew);
if (data.moving || skew === 0)
clearInterval(data.timer);
}, 20);
data.moving = false;
};
/**
* The mouse up event.
* @param {Object} event
*/
Draggable.prototype.onMouseUp = function(event) {
this.setSkew('');
// Remove useless events.
window.removeEventListener('mousemove', this.mouseMove, false);
window.removeEventListener('mousemove', this.mouseUp, false);
};