Drag and Resize with MochiKit Signals

14 views
Skip to first unread message

Andy Fischer

unread,
Sep 6, 2006, 4:21:02 PM9/6/06
to MochiKit
Hello.

I have a problem with calculating the Position of draggable element in
the following code. I'm not really familiar with Object Oriented
Javscript nor with MochiKIt API.
I hope it's a stupid error which can be fixed easily.

I try to implement draggable and resizable <div>-elements with
MochiKit.Signals.
Because I don't have droppable elements, I adopted a proposal from a
thread (drag and drop, rubberband/resize/stretch example) in august.
I used the draggable example as base and did not use DragandDrop.
The event handler for mouse movements is used to change the cursor.
When draggging is started the position of the mouse within the
draggable element is used to determine the type of resize or move
action and the original position and dimension is saved.

In the drag-function the new coordinates and dimensions of the element
are calculated.
For the move operation I kept the original code from the draggable
example.
But the behavior of the resize operations is unexpected, especially
when the diplacement from the start position increases.
It looks like the saved startPosition is not constant but is
recalculated with each event.
Is this a Javascript issue? Is the saved _StartPos a function which is
called each time instead of the evaluated position?

Please enlighten me...

--------8<--------------------------8<--------------------------8<------------
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Extended Signal Example</title>
<style type="text/css" media="screen">
h1 {
font-size: 2em;
color: #4B4545;
text-align: center;
}
.draggable
{
color: white;
cursor: move;
font-size: 25px;
height: 100px;
line-height: 100px;
position: absolute;
text-align: center;
top: 200px;
width: 100px;
}

.blue { background: blue; }
.green { background: green; }
.red { background: red; }
.white
{
background: white;
border: 1px solid black;
color: black;
}
</style>

<script type="text/javascript" src="MochiKit/MochiKit.js"></script>
<script type="text/javascript">
Drag = {
XRange: null,
YRange: null,
_dmove: null,
_down: null,

_StartMouse: null,
_StartPos: null,
_StartDim: null,
_DragAction: null,

start: function(e) {
e.stop();

// We need to remember what we're dragging.
Drag._target = e.target();

if (XRange == 0)
{
// Mouse is close to left hand side
if (YRange == 0) // Upper left corner
Drag._DragAction = 1;
else if (YRange == 1) // Left edge
Drag._DragAction = 2;
else if (YRange == 2) // Lower left corner
Drag._DragAction = 3;
}
else if (XRange == 2)
{
// Mouse is close to right hand side
if (YRange == 0) // Upper right corner
Drag._DragAction = 7;
else if (YRange == 1) // Right edge
Drag._DragAction = 6;
else if (YRange == 2) // LOwer right corner
Drag._DragAction = 5;
}
else
{
// Mouse is in the X-center
if (YRange == 0) // Upper edge
Drag._DragAction = 8;
else if (YRange == 1) // Center
Drag._DragAction = 9;
else if (YRange == 2) // Lower edge
Drag._DragAction = 4;
}

Drag._StartMouse = e.mouse().page;
Drag._StartPos = getElementPosition(Drag._target);
Drag._StartDim = getElementDimensions(Drag._target);
log('Start: StartMouse: '+ Drag._StartMouse+' StartPos:
'+Drag._StartPos+' StartDim: '+Drag._StartDim);

// This was the original code from the sample in
example\Draggable
Drag._offset = Drag._diff(
e.mouse().page,
getElementPosition(Drag._target));

Drag._dmove = connect(document, 'onmousemove', Drag._drag);
Drag._down = connect(document, 'onmouseup', Drag._stop);
},

_offset: null,
_target: null,

_diff: function(lhs, rhs) {
return new MochiKit.Style.Coordinates(lhs.x - rhs.x, lhs.y
- rhs.y);
},

move: function(e) {
var cXMin = 4;
var cYMin = 4;

var MPos = e.mouse().page;
var elem = e.target();
var EPos = getElementPosition(elem);
var EDim = getElementDimensions(elem);

// log('MMove '+MPos+' Pos: '+EPos);
if (MPos.x -EPos.x < cXMin)
XRange = 0;
else if (EDim.w - (MPos.x -EPos.x) < cXMin)
XRange = 2;
else
XRange = 1;

if (MPos.y -EPos.y < cYMin)
YRange = 0;
else if (EDim.h - (MPos.y -EPos.y) < cYMin)
YRange = 2;
else
YRange = 1;

if (XRange == 0)
{
// Left hand side
if (YRange == 0)
MochiKit.DOM.updateNodeAttributes(elem,
{'style':{'cursor':'nw-resize'}});
else if (YRange == 1)
MochiKit.DOM.updateNodeAttributes(elem,
{'style':{'cursor':'w-resize'}});
else if (YRange == 2)
MochiKit.DOM.updateNodeAttributes(elem,
{'style':{'cursor':'sw-resize'}});
}
else if (XRange == 2)
{
// right hand side
if (YRange == 0)
MochiKit.DOM.updateNodeAttributes(elem,
{'style':{'cursor':'ne-resize'}});
else if (YRange == 1)
MochiKit.DOM.updateNodeAttributes(elem,
{'style':{'cursor':'e-resize'}});
else if (YRange == 2)
MochiKit.DOM.updateNodeAttributes(elem,
{'style':{'cursor':'se-resize'}});
}
else
{
if (YRange == 0)
MochiKit.DOM.updateNodeAttributes(elem,
{'style':{'cursor':'n-resize'}});
else if (YRange == 1)
MochiKit.DOM.updateNodeAttributes(elem,
{'style':{'cursor':'move'}});
else if (YRange == 2)
MochiKit.DOM.updateNodeAttributes(elem,
{'style':{'cursor':'s-resize'}});
}

},

_drag: function(e) {
e.stop();
// Drag._StartPos contains the element position , when the
drag hast starteds
var vDiff = Drag._diff(e.mouse().page, Drag._StartMouse);
var Dim = Drag._StartDim;
var Pos = Drag._StartPos;
log('Drag: Mouse: '+e.mouse().page+' Pos: '+
Drag._StartPos+' Dim: '+Drag._StartDim);

switch (Drag._DragAction)
{
case 1: // NW-Resize
Dim.w = Dim.w - vDiff.x;
Dim.h = Dim.h - vDiff.y;
Pos.x = Pos.x + vDiff.x;
Pos.y = Pos.y + vDiff.y;
log('NW-Resize: Pos: '+Pos+' Dim: '+Dim+' vDiff:
'+vDiff);
setElementPosition(Drag._target,Pos);
setElementDimensions(Drag._target,Dim);
break;
case 2: // W-Resize
Dim.w = Dim.w - vDiff.x;
Pos.x = Pos.x + vDiff.x;
log('W-Resize: Pos: '+Pos+' Dim: '+Dim+' vDiff:
'+vDiff);
setElementPosition(Drag._target,Pos);
setElementDimensions(Drag._target,Dim);
break;
case 3: // SW-Resize
Dim.w = Dim.w - vDiff.x;
Dim.h = Dim.h + vDiff.y;
Pos.x = Pos.x + vDiff.x;
log('SW-Resize: Pos: '+Pos+' Dim: '+Dim+' vDiff:
'+vDiff);
setElementPosition(Drag._target,Pos);
setElementDimensions(Drag._target,Dim);
break;
case 4: // S-Resize
Dim.h = Dim.h + vDiff.y;
log('S-Resize: Pos: '+Pos+' Dim: '+Dim+' vDiff:
'+vDiff);
setElementPosition(Drag._target,Pos);
setElementDimensions(Drag._target,Dim);
break;
case 5: // SE-Resize
Dim.w = Dim.w + vDiff.x;
Dim.h = Dim.h + vDiff.y;
log('SE-Resize: Pos: '+Pos+' Dim: '+Dim+' vDiff:
'+vDiff);
setElementPosition(Drag._target,Pos);
setElementDimensions(Drag._target,Dim);
break;
case 6: // E-Resize
Dim.w = Dim.w + vDiff.x;
log('E-Resize: Pos: '+Pos+' Dim: '+Dim+' vDiff:
'+vDiff);
setElementPosition(Drag._target,Pos);
setElementDimensions(Drag._target,Dim);
break;
case 7: // NE-Resize
Dim.w = Dim.w + vDiff.x;
Dim.h = Dim.h - vDiff.y;
Pos.y = Pos.y + vDiff.x;
log('NE-Resize: Pos: '+Pos+' Dim: '+Dim+' vDiff:
'+vDiff);
setElementPosition(Drag._target,Pos);
setElementDimensions(Drag._target,Dim);
break;
case 8: // N-Resize
Dim.h = Dim.h - vDiff.y;
Pos.y = Pos.y + vDiff.y;
log('N-Resize: Pos: '+Pos+' Dim: '+Dim+' vDiff:
'+vDiff);
setElementPosition(Drag._target,Pos);
setElementDimensions(Drag._target,Dim);
break;
case 9:
Pos.x = Pos.x + vDiff.x;
Pos.y = Pos.y + vDiff.y;
// log('Move: Pos: '+Pos+' Dim: '+Dim+' vDiff:
'+vDiff);
// setElementPosition(Drag._target,Pos);

// Original code from draggable.js
log('Move: Mouse: '+e.mouse().page+' Offset:
'+Drag._offset);
setElementPosition(
Drag._target,
Drag._diff(e.mouse().page, Drag._offset));
break;
}
},

_stop: function(e) {
Drag._DragAction = 0;

disconnect(Drag._dmove);
disconnect(Drag._down);
}
}; // of Drag

connect(window, 'onload',
function() {
/*
Find all DIVs tagged with the draggable class, and connect
them to
the Drag handler.
*/
var d = getElementsByTagAndClassName('DIV', 'draggable');
forEach(d,
function(elem) {
connect(elem, 'onmousedown', Drag.start);
connect(elem, 'onmousemove', Drag.move);
});
});
</script>
</head>
<body>

<h1>
Dragging and Resizing with MochiKit's Signals
</h1>
<p>
This is an example of one might implement a drag handler with
MochiKit&#8217;s Signal.
Move the mouse cursor over one of the rectangles. The cursor
will change
its shape, to show the different resize and move actions.
</p>

<div class="draggable red" id="drag_red" style="left:
10px;">R</div>
<div class="draggable green" id="drag_green" style="left:
120px;">G</div>
<div class="draggable blue" id="drag_blue" style="left:
230px;">B</div>
<div class="draggable white" id="drag_white" style="left:
340px;">W</div>
</body>
</html>
--------8<--------------------------8<--------------------------8<------------

I hope the code sample above is not offending your rules about posting
code on the list.

Eric Waldheim

unread,
Sep 6, 2006, 8:29:17 PM9/6/06
to MochiKit
I think you're missing an update of Drag._StartMouse in _drag.

I added the last line here and the example worked:

_drag: function(e) {
e.stop();
// Drag._StartPos contains the element position , when
the drag hast starteds
var vDiff = Drag._diff(e.mouse().page, Drag._StartMouse);

Drag._StartMouse = e.mouse().page;

Eric

Andy Fischer

unread,
Sep 7, 2006, 4:28:29 AM9/7/06
to MochiKit
Eric Waldheim schrieb:

Thanks a lot!

I tried to calculate Position from the start of drag, to keep the
original position.
With the update of _StartPos within _drag() I do incremental
positioning.
This is fine for now.

During the next days I'll try to implement the special cases to prevent
shrinking rectangles to zero.

Andy

Reply all
Reply to author
Forward
0 new messages