I am using JavaScript and trying to make a skew effect on a div.
First, take a look at this video: http://www.youtube.com/watch?v=ny5Uy81smpE (0:40-0:60 should be enough). The video shows some nice transformations (skew) when you move the window. What I want to do is the same thing: to skew a div when I move it.
Currently I just have a plain simple div:
<div id="a" style="background: #0f0; position: absolute; left: 0px; top: 0px;"></div>
I have done a simple skew transformation using the CSS3’s transform property, but my implementation is buggy. Are there good tutorials or maths sites or resources that describe the logic behind this? I know JavaScript and CSS well enough to implement, if I just knew the logic and maths. I tried reading FreeWins source code, but I am not good in C.
I am accepting any resourceful answers or pseudo code. My dragging system is part of a bigger system, thus, now that I post some real code, it does not work without giving you the entire system (that I can not do at this point). So, you can’t run this code as is. The code I use is this (slightly modified though) to demonstrate my idea:
/**
* The draggable object.
*/
Draggable = function(targetElement, options) {
this.targetElement = targetElement;
// Initialize drag data.
this.dragData = {
startX: null,
startY: null,
lastX: null,
lastY: null,
offsetX: null,
offsetY: null,
lastTime: null,
occuring: false
};
// Set the cursor style.
targetElement.style.cursor = 'move';
// The element to move.
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);
};
};
/**
* The mouse down event.
* @param {Object} event
*/
Draggable.prototype.onMouseDown = function(event) {
// New drag event.
if (this.dragData.occuring === false) {
this.dragData.occuring = true;
this.dragData.startX = this.dragData.lastX = event.clientX;
this.dragData.startY = this.dragData.lastY = event.clientY;
this.dragData.offsetX = parseInt(this.applyTo.style.left, 10) - event.clientX;
this.dragData.offsetY = parseInt(this.applyTo.style.top, 10) - event.clientY;
this.dragData.lastTime = (new Date()).getTime();
// Mouse up and move events.
var me = this;
window.addEventListener('mousemove', this.mouseMove, false);
window.addEventListener('mouseup', this.mouseUp, false);
}
};
/**
* The mouse movement event.
* @param {Object} event
*/
Draggable.prototype.onMouseMove = function(event) {
if (this.dragData.occuring === true) {
// He is dragging me now, we move if there is need for that.
var moved = (this.dragData.lastX !== event.clientX || this.dragData.lastY !== event.clientY);
if (moved === true) {
var element = this.applyTo;
// The skew animation. :)
var skew = (this.dragData.lastX - event.clientX) * 1;
var limit = 25;
if (Math.abs(skew) > limit) {
skew = limit * (skew > 0 ? 1 : -1);
}
var transform = 'translateX(' + (event.clientX + this.dragData.offsetX - parseInt(element.style.left, 10)) + 'px)';
transform += 'translateY(' + (event.clientY + this.dragData.offsetY - parseInt(element.style.top, 10)) + 'px)';
transform += 'skew(' + skew + 'deg)';
element.style.MozTransform = transform;
element.style.webkitTransform = transform;
this.dragData.lastX = event.clientX;
this.dragData.lastY = event.clientY;
this.dragData.lastTime = (new Date()).getTime();
}
}
};
/**
* The mouse up event.
* @param {Object} event
*/
Draggable.prototype.onMouseUp = function(event) {
this.dragData.occuring = false;
var element = this.applyTo;
// Reset transformations.
element.style.MozTransform = '';
element.style.webkitTransform = '';
// Save the new position.
element.style.left = (this.dragData.lastX + this.dragData.offsetX) + 'px';
element.style.top = (this.dragData.lastY + this.dragData.offsetY) + 'px';
// Remove useless events.
window.removeEventListener('mousemove', this.mouseMove, false);
window.removeEventListener('mousemove', this.mouseUp, false);
};
Currently my dragging system is buggy and simple. I need more information on the logic that I should be applying.
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:
topandleftpositions during initialization (getBoundingClientRect)this.dragDataandelement.stylefor shortness and faster executiondragDatacan be initialized as an empty object. It’s fine in javascript. You can add properties later.optionsshould be conditionally initialized as an empty object, so that you can take zero optionsmovedanddragData.occuringwere totally useless because of the event managementpreventDefaultis needed in order not to select text during draggingz-indexesto be the active element always visibleHave fun!
Code [See it in action]