Calculating window dragging and skewing in JavaScript
Wow, the idea rocks. :) I've cleaned your code a bit, and solved the problems with initialization. Now it works fine for me on Firefox and Chrome (even though you said it shouldn't).
A few notes:
- you need to grab the starting
top
andleft
positions during initialization (getBoundingClientRect) - store references like
this.dragData
andelement.style
for shortness and faster execution dragData
can be initialized as an empty object. It's fine in javascript. You can add properties later.options
should be conditionally initialized as an empty object, so that you can take zero optionsmoved
anddragData.occuring
were totally useless because of the event managementpreventDefault
is needed in order not to select text during dragging- you may want to keep track of
z-indexes
to be the active element always visible
Have fun!
Code [See it in action]
/** * 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);};