transformlist branch: Fix proper sizing of selector boxes

git-svn-id: http://svg-edit.googlecode.com/svn/branches/transformlist@906 eee81c28-f429-11dd-99c0-75d572ba1ddd
master
Jeff Schiller 2009-11-04 15:30:10 +00:00
parent b0d565bdeb
commit 516703cac7
1 changed files with 113 additions and 49 deletions

View File

@ -1,11 +1,10 @@
/*
TODOs for TransformList:
* Fix proper selector box sizing
* Fix moving/resizing/rotating of groups (pummel the transforms down to the children?)
* Ensure resizing in negative direction works
* Ensure ungrouping works
* Ensure undo still works properly
* Ensure resizing in negative direction works (nope! broken!)
* Ensure ungrouping works (surely broken)
* Ensure undo still works properly (nope! broken!)
*/
/*
TODOs for Localizing:
@ -399,6 +398,7 @@ function BatchCommand(text) {
};
};
// TODO: update this function to not use the cur_bbox anymore
this.resize = function(cur_bbox) {
var selectedBox = this.selectorRect;
var selectedGrips = this.selectorGrips;
@ -423,11 +423,52 @@ function BatchCommand(text) {
});
}
var l=bbox.x-offset, t=bbox.y-offset, w=bbox.width+(offset<<1), h=bbox.height+(offset<<1);
// loop and transform our bounding box until we reach our first rotation
var tlist = canvas.getTransformList(this.selectedElement);
var m = svgroot.createSVGMatrix();
var bFoundRotate = false;
var topleft = {x:l*current_zoom,y:t*current_zoom},
botright = {x:(l+w)*current_zoom,y:(t+h)*current_zoom};
var tstr = "";
var i = tlist.numberOfItems;
// loop backwards through the list of transforms and update the selector box coords
while (i--) {
var xform = tlist.getItem(i);
// once we hit a rotate, we stop doing this and just save up the transform
// string fragment and apply it to the selector group
if (xform.type == 4) {
bFoundRotate = true;
}
if (bFoundRotate) {
tstr = transformToString(xform) + " " + tstr;
}
else if(!bFoundRotate) {
m = matrixMultiply(xform.matrix,m);
}
}
// apply the transforms
topleft = transformPoint( topleft.x, topleft.y, m );
botright = transformPoint( botright.x, botright.y, m );
this.selectorGroup.setAttribute("transform", "");
this.selectorGroup.removeAttribute("transform");
if (tstr != "") {
this.selectorGroup.setAttribute("transform", tstr);
}
l = topleft.x;
t = topleft.y;
w = botright.x - topleft.x;
h = botright.y - topleft.y;
// TODO: handle negative?
var sr_handle = svgroot.suspendRedraw(100);
l*=current_zoom;
t*=current_zoom;
w*=current_zoom;
h*=current_zoom;
// TODO: move to a path instead of a rect and then plot the
// grip coordinates more carefully
assignAttributes(selectedBox, {
'x': l,
'y': t,
@ -454,19 +495,6 @@ function BatchCommand(text) {
assignAttributes(this.rotateGripConnector, { x1: l+w/2, y1: t-20, x2: l+w/2, y2: t });
assignAttributes(this.rotateGrip, { cx: l+w/2, cy: t-20 });
// empty out the transform attribute
this.selectorGroup.setAttribute("transform", "");
this.selectorGroup.removeAttribute("transform");
// align selector group with element coordinate axes
var elem = this.selectedElement;
var transform = elem.getAttribute("transform");
var angle = canvas.getRotationAngle(elem);
if (angle) {
var cx = round(oldbox.x + oldbox.width/2) * current_zoom
cy = round(oldbox.y + oldbox.height/2) * current_zoom;
this.selectorGroup.setAttribute("transform", "rotate("+angle+" " + cx + "," + cy + ")");
}
svgroot.unsuspendRedraw(sr_handle);
};
@ -596,8 +624,8 @@ function BatchCommand(text) {
// SVGTransform replaceItem ( in SVGTransform newItem, in unsigned long index )
// SVGTransform removeItem ( in unsigned long index )
// SVGTransform appendItem ( in SVGTransform newItem )
// SVGTransform createSVGTransformFromMatrix ( in SVGMatrix matrix );
// SVGTransform consolidate ( );
// NOT IMPLEMENTED: SVGTransform createSVGTransformFromMatrix ( in SVGMatrix matrix );
// NOT IMPLEMENTED: SVGTransform consolidate ( );
// }
// **************************************************************************************
var svgTransformLists = {};
@ -610,23 +638,7 @@ function BatchCommand(text) {
var concatMatrix = svgroot.createSVGMatrix();
for (var i = 0; i < this.numberOfItems; ++i) {
var xform = this._list.getItem(i);
var m = xform.matrix;
switch (xform.type) {
case 2: // translate
tstr += "translate(" + m.e + "," + m.f + ") ";
break;
case 3: // scale
if (m.a == m.d) tstr += "scale(" + m.a + ") ";
else tstr += "scale(" + m.a + "," + m.d + ") ";
break;
case 4: // rotate (with a translate)
var bbox = canvas.getBBox(this._elem);
var K = 1 - m.a;
var ty = ( K * m.f + m.b*m.e ) / ( K*K + m.b*m.b );
var tx = ( m.e - m.b * ty ) / K;
tstr += "rotate(" + xform.angle + " " + [tx,ty].join(",") + ") ";
break;
}
tstr += transformToString(xform) + " ";
}
this._elem.setAttribute("transform", tstr);
};
@ -1375,8 +1387,6 @@ function BatchCommand(text) {
dx = cx - newcenter.x;
dy = cy - newcenter.y;
// TODO: fix this so that it determines the true translation
// required so that the rotational center lines up
remap = function(x,y) {
return { x: x + dx, y: y + dy };
};
@ -2103,6 +2113,54 @@ function BatchCommand(text) {
return { x: m.a * x + m.c * y + m.e, y: m.b * x + m.d * y + m.f};
};
// This is provided because WebKit doesn't implement multiply() correctly
// on the SVGMatrix interface. See https://bugs.webkit.org/show_bug.cgi?id=16062
// It returns a SVGMatrix that is the multiplication m1*m2.
var matrixMultiply = function(m1, m2) {
var a = m1.a*m2.a + m1.c*m2.b,
b = m1.b*m2.a + m1.d*m2.b,
c = m1.a*m2.c + m1.c*m2.d,
d = m1.b*m2.c + m1.d*m2.d,
e = m1.a*m2.e + m1.c*m2.f + m1.e,
f = m1.b*m2.e + m1.d*m2.f + m1.f;
var m = svgroot.createSVGMatrix();
m = m.translate(e,f);
m = m.scaleNonUniform(a,d);
m = m.skewX( Math.atan(c) );
m = m.skewY( Math.atan(b) );
return m;
}
// This returns a single matrix Transform for a given Transform List
// (this is the equivalent of SVGTransformList.consolidate() but unlike
// that method, this one does not modify the actual SVGTransformList)
var transformListToTransform = function(tlist) {
var m = svgroot.createSVGMatrix();
for (var i = 0; i < tlist.numberOfItems; ++i) {
m = matrixMultiply(m, tlist.getItem(i).matrix);
}
return svgroot.createSVGTransformFromMatrix(m);
};
// converts a string equivalent of a SVGTransform
var transformToString = function(xform) {
var m = xform.matrix;
switch(xform.type) {
case 2: // TRANSFORM
return "translate(" + m.e + "," + m.f + ")";
case 3: // SCALE
if (m.a == m.d) return "scale(" + m.a + ")";
return "scale(" + m.a + "," + m.d + ")";
case 4: // ROTATE
// TODO: handle divide by zero here
var K = 1 - m.a;
var cy = ( K * m.f + m.b*m.e ) / ( K*K + m.b*m.b );
var cx = ( m.e - m.b * cy ) / K;
return "rotate(" + xform.angle + " " + cx + "," + cy + ")";
// TODO: matrix, skewX, skewY
}
};
// - when we are in a create mode, the element is added to the canvas
// but the action is not recorded until mousing up
// - when we are in select mode, select the element, remember the position
@ -2484,7 +2542,7 @@ function BatchCommand(text) {
}
// update our internal bbox that we're tracking while dragging
selectorManager.requestSelector(selected).resize(box);
selectorManager.requestSelector(selected).resize();//box); // TODO: remove box arg
// now transform delta mouse movement into a translation in the
// coordinate space of the mouse target
@ -2650,7 +2708,7 @@ function BatchCommand(text) {
}
}
selectorManager.requestSelector(selected).resize(selectedBBox);
selectorManager.requestSelector(selected).resize();//selectedBBox); // TODO: remove box arg
break;
case "zoom":
x *= current_zoom;
@ -3406,7 +3464,7 @@ function BatchCommand(text) {
if (selectedElements[i] == null) break;
if(selectedElements[i].tagName != 'g') {
// Not needed for groups (incorrectly resizes elems), possibly not needed at all?
selectorManager.requestSelector(selectedElements[i]).resize(selectedBBoxes[i]);
selectorManager.requestSelector(selectedElements[i]).resize();//selectedBBoxes[i]); // TODO: remove box arg
}
}
}
@ -4919,7 +4977,13 @@ function BatchCommand(text) {
if (preventUndo) {
// we don't need to undo, just update the transform list
tlist.replaceItem(newrot, 0);
// Opera Bug: for whatever reason, sometimes Opera doesn't let you
// replace the 0th transform (perhaps if it's an identity matrix?)
try {
tlist.replaceItem(newrot, 0);
} catch(e) {
tlist.insertItemBefore(newrot,0);
}
}
else {
// FIXME: we need to do it, then undo it, then redo it so it can be undo-able! :)
@ -4935,7 +4999,7 @@ function BatchCommand(text) {
setPointContainerTransform(elem.getAttribute("transform"));
}
var selector = selectorManager.requestSelector(selectedElements[0]);
selector.resize(bbox);
selector.resize();//bbox); // TODO: remove box arg
selector.updateGripCursors(val);
};
@ -5229,7 +5293,7 @@ function BatchCommand(text) {
}
// Timeout needed for Opera & Firefox
setTimeout(function() {
selectorManager.requestSelector(elem).resize(elem.getBBox());
selectorManager.requestSelector(elem).resize();//elem.getBBox()); // TODO: remove box arg
},0);
// if this element was rotated, and we changed the position of this element
// we need to update the rotational transform attribute
@ -5473,7 +5537,7 @@ function BatchCommand(text) {
if (cmd) {
batchCmd.addSubCommand(cmd);
}
selectorManager.requestSelector(selected).resize(selectedBBoxes[i]);
selectorManager.requestSelector(selected).resize();//selectedBBoxes[i]);
}
}
if (!batchCmd.isEmpty()) {