我正在使用RaphaelJS 2.0在div中创建多个形状。每个形状都需要能够独立地在div的范围内拖放。双击形状后,该形状需要旋转90度。然后可以拖放它并再次旋转。
我已经在fiddler上加载了一些代码:http://jsfiddle.net/QRZMS/。基本上就是这样:
window.onload = function () {
var angle = 0;
var R = Raphael("paper", "100%", "100%"),
shape1 = R.rect(100, 100, 100, 50).attr({ fill: "red", stroke: "none" }),
shape2 = R.rect(200, 200, 100, 50).attr({ fill: "green", stroke: "none" }),
shape3 = R.rect(300, 300, 100, 50).attr({ fill: "blue", stroke: "none" }),
shape4 = R.rect(400, 400, 100, 50).attr({ fill: "black", stroke: "none" });
var start = function () {
this.ox = this.attr("x");
this.oy = this.attr("y");
},
move = function (dx, dy) {
this.attr({ x: this.ox + dx, y: this.oy + dy });
},
up = function () {
};
R.set(shape1, shape2, shape3, shape4).drag(move, start, up).dblclick(function(){
angle -= 90;
shape1.stop().animate({ transform: "r" + angle }, 1000, "<>");
});
}
拖放工作正常,其中一个形状在双击时旋转。但是,有两个问题/问题:
如何自动将旋转附加到每个形状上,而无需将每个项目参考硬编码到旋转方法中?即我只想绘制一次形状,然后将它们全部自动暴露给相同的行为,这样它们就可以独立地拖放/旋转,而不必将该行为明确地应用于每个形状。
旋转形状后,它不再正确拖动 - 就好像拖动鼠标移动与形状的原始方向相关,而不是在旋转形状时更新。我怎样才能让它正常工作,以便可以多次拖动和旋转形状,Seamlessley?
非常感谢任何指示!
答案 0 :(得分:13)
我已经多次尝试过围绕新的变换引擎,但无济于事。所以,我已经回到了第一原则。
在尝试计算出不同变换的影响后,我终于设法正确地拖放了经历了几次变换的对象 - t,T,... t,... T,r,R等...
所以,这是解决方案的关键
var ox = 0;
var oy = 0;
function drag_start(e)
{
};
function drag_move(dx, dy, posx, posy)
{
r1.attr({fill: "#fa0"});
//
// Here's the interesting part, apply an absolute transform
// with the dx,dy coordinates minus the previous value for dx and dy
//
r1.attr({
transform: "...T" + (dx - ox) + "," + (dy - oy)
});
//
// store the previous versions of dx,dy for use in the next move call.
//
ox = dx;
oy = dy;
}
function drag_up(e)
{
// nothing here
}
就是这样。愚蠢的简单,我确信它已经发生在很多人身上,但也许有人会发现它很有用。
这是一个fiddle供你玩。
... this是初始问题的有效解决方案。
答案 1 :(得分:4)
答案 2 :(得分:3)
正如amadan所说,当多个事物具有相同(初始)属性/属性时,创建函数通常是个好主意。这确实是你第一个问题的答案。至于第二个问题,这有点棘手。
旋转Rapheal对象时,坐标平面也是如此。出于某种原因,dmitry和网上的一些其他来源似乎都认为这是实施它的正确方法。我和你一样,不同意。我没有找到一个全面的好解决方案,但我做了一个工作来创造一个解决方案。我将简要解释然后显示代码。
假设您只是将形状旋转90度(如果不是变得更难),您可以确定如何操纵坐标。
var R = Raphael("paper", "100%", "100%");
//create the custom attribute which will hold the current rotation of the object {0,1,2,3}
R.customAttributes.rotPos = function (num) {
this.node.rotPos = num;
};
var shape1 = insert_rect(R, 100, 100, 100, 50, { fill: "red", stroke: "none" });
var shape2 = insert_rect(R, 200, 200, 100, 50, { fill: "green", stroke: "none" });
var shape3 = insert_rect(R, 300, 300, 100, 50, { fill: "blue", stroke: "none" });
var shape4 = insert_rect(R, 400, 400, 100, 50, { fill: "black", stroke: "none" });
//Generic insert rectangle function
function insert_rect(paper,x,y, w, h, attr) {
var angle = 0;
var rect = paper.rect(x, y, w, h);
rect.attr(attr);
//on createion of the object set the rotation position to be 0
rect.attr({rotPos: 0});
rect.drag(drag_move(), drag_start, drag_up);
//Each time you dbl click the shape, it gets rotated. So increment its rotated state (looping round 4)
rect.dblclick(function(){
var pos = this.attr("rotPos");
(pos++)%4;
this.attr({rotPos: pos});
angle -= 90;
rect.stop().animate({transform: "r" + angle}, 1000, "<>");
});
return rect;
}
//ELEMENT/SET Dragger functions.
function drag_start(e) {
this.ox = this.attr("x");
this.oy = this.attr("y");
};
//Now here is the complicated bit
function drag_move() {
return function(dx, dy) {
//default position, treat drag and drop as normal
if (this.attr("rotPos") == 0) {
this.attr({x: this.ox + dx, y: this.oy + dy});
}
//The shape has now been rotated -90
else if (this.attr("rotPos") == 1) {
this.attr({x:this.ox-dy, y:this.oy + dx});
}
else if (this.attr("rotPos") == 2) {
this.attr({x: this.ox - dx, y: this.oy - dy});
}
else if (this.attr("rotPos") == 3) {
this.attr({x:this.ox+dy, y:this.oy - dx});
}
}
};
function drag_up(e) {
}
我真的无法用简洁的方式来解释drag_move的工作原理。我认为你最好看看代码并看看它是如何工作的。基本上,您只需要弄清楚如何从这个新的旋转状态处理x和y变量。没有我绘制大量图形,我不确定我是否足够清楚。 (我做了很多事情,试着弄清楚应该做些什么)。
这种方法有一些缺点:
我假设您使用变换的原因是您可以为旋转设置动画。如果没有必要,那么你可以使用.rotate()
函数,该函数总是围绕元素的中心旋转,因此将消除我提到的第二个缺点。
这不是一个完整的解决方案,但它绝对应该让你走正确的道路。我很想看到一个完整的工作版本。
我还在jsfiddle上创建了一个版本,你可以在这里查看:http://jsfiddle.net/QRZMS/3/
祝你好运。答案 3 :(得分:1)
我通常会为我的形状创建一个对象,并将事件处理写入对象。
function shape(x, y, width, height, a)
{
var that = this;
that.angle = 0;
that.rect = R.rect(x, y, width, height).attr(a);
that.rect.dblclick(function() {
that.angle -= 90;
that.rect.stop().animate({
transform: "r" + that.angle }, 1000, "<>");
});
return that;
}
在上面,构造函数不仅创建了矩形,还设置了双击事件。
需要注意的一点是,对象的引用存储在&#34;&#34;中。这是因为&#34;这个&#34;参考变化取决于范围。在dblClick函数中,我需要从对象中引用 rect 和 angle 值,因此我使用存储的引用 that.rect 和<强> that.angle 强>
请参阅此example(从稍微狡猾的先前实例更新)
可能有更好的方法来做你需要的事情,但这应该适合你。
希望有所帮助,
尼克
附录:Dan,如果你真的坚持这一点,并且没有Raphael2给你的一些东西,我建议你回到拉斐尔1.5。 X。变换刚刚添加到Raphael2中,旋转/翻译/缩放代码在1.5.2中完全不同(并且更容易)。
看着我,更新我的帖子,希望有业力......
答案 4 :(得分:1)
如果您不想使用ElbertF库,可以在极坐标中转换笛卡尔坐标。
必须添加或删除角度并在笛卡尔坐标系中再次变换。
我们可以看到这个例子,直接旋转隆隆声并移动。
<强> HTML 强>
<div id="foo">
</div>
<强> JAVASCRIPT 强>
var paper = Raphael(40, 40, 400, 400);
var c = paper.rect(40, 40, 40, 40).attr({
fill: "#CC9910",
stroke: "none",
cursor: "move"
});
c.transform("t0,0r45t0,0");
var start = function () {
this.ox = this.type == "rect" ? this.attr("x") : this.attr("cx");
this.oy = this.type == "rect" ? this.attr("y") : this.attr("cy");
},
move = function (dx, dy) {
var r = Math.sqrt(Math.pow(dx, 2) + Math.pow(dy, 2));
var ang = Math.atan2(dy,dx);
ang = ang - Math.PI/4;
dx = r * Math.cos(ang);
dy = r * Math.sin(ang);
var att = this.type == "rect" ? { x: this.ox + dx, y: this.oy + dy} : { cx: this.ox + dx, cy: this.oy + dy };
this.attr(att);
},
up = function () {
};
c.drag(move, start, up);?
<强>样本强>
http://jsfiddle.net/Ef83k/74/
答案 5 :(得分:0)
我的第一个想法是使用getBBox(false)来捕获变换后对象的x,y坐标,然后从画布中删除原始Raphael obj的theChild(),然后使用getBBox中的坐标数据重绘对象(false )。一个黑客,但我有它的工作。
但需注意一点:因为getBBox(false)返回的对象是对象的CORNER坐标(x,y),你需要通过这样做来计算重绘对象的中心... x = box ['x'] +(box ['width'] / 2); y = box ['y'] +(box ['height'] / 2);
,其中 box = shapeObj.getBBox(false);
解决同样问题的另一种方法