Raphael.js attr 函数设置了错误的值
Raphael.js attr function sets wrong value
我正在使用 Raphael.js 实现拖放系统。为此,我将原始的 x 和 y 位置存储在 mousedown 上,如果在 mouseup 上发生碰撞,我想将位置重置为原始位置。这是执行重置的代码("this" 指的是这里的 raphael 对象):
var transformString = "t" + this.original_x + "," + this.original_y;
this.attr("transform", transformString);
奇怪的是,设置属性后,转换字符串改变了几个像素。我调试了这个:
var transformString = "t" + this.original_x + "," + this.original_y;
this.attr("transform", transformString);
console.log("transformString: " + transformString);
console.log("transformAttrib: " + this.attr("transform"));
据我所知,在任何情况下,两个记录的值都应该相等。但它们有时会相差 20 像素。有人知道这里发生了什么吗?
E:这是一个简化版本,没有碰撞测试,仍然重现了错误:http://jsfiddle.net/6ozsfdaf
我不太确定为什么会出现这个问题,但我想知道这是否是更好的解决方案。与其每次都解析字符串,不如存储转换并使用它。
我也将其切换为使用 transform() 方法,而不是 attr(transform:..) 方法。虽然我认为这通常会起作用,但它在逻辑上不太正确,因为 SVG 属性不采用 Raphael 转换字符串,但我认为 Raph 会拦截并处理它(但可能更容易出错)。
在转换字符串中还值得牢记,'t' 是相对转换而 'T' 是绝对转换(我认为这不是问题,因为没有前面的转换,但我想知道它是否也相关)。
this.start = function() {
if (this.reference.static) return;
this.original_t = this.transform();
this.animate({r: 70, opacity: 0.25}, 500, ">");
};
this.move = function(dx, dy) {
this.transform( this.original_t + 't' + dx + ',' + dy);
};
this.up = function() {
this.transform( this.original_t );
console.log("transformString: " + this.original_t);
console.log("transformAttrib: " + this.transform());
this.attr({fill: "#fff"});
this.animate({r: 50, opacity: 1}, 500, ">");
};
我不确定为什么会这样。我什至尝试使用 onmousedown
事件在 onstart
之前捕获坐标,即使那样也没有用。 Raphael 提供的使用 getBBox()
获取坐标的不同方法,直接访问 x
和 y
,也没有帮助。
所以我的想法是,我们应该手动维护和跟踪坐标。所以我使用了你的 original_x
和 original_y
变量,它们在你创建并设置了一些转换值之后捕获了 <path>
的位置。下面是相同的代码
这是工作 fiddle。
this.raph = R.path(svgPath).attr({
stroke: "hsb(0, 1, 1)",
fill: "#fff",
opacity: 1.0,
cx: 100,
cy: 900
}).transform("t" + x + "," + y);
this.raph.original_x = x;
this.raph.original_y = y;
//comment the lines in start method which captures original_x and original_y
//this.original_x = Raphael.parseTransformString(this.attr("transform"))[0][1];
//this.original_y = Raphael.parseTransformString(this.attr("transform"))[0][2];
有关跟踪坐标的更多信息:
我们还会有一个坐标 updated_x
和 updated_y
,它们将在 move
方法中更新。 onFinish/onUp 方法,我们可以检查是否应该更新新位置。在这里,它只是询问是否应该更新新位置,并根据我们的输入设置最终结果。
检查这个 fiddle:
this.start = function() {
if (this.reference.static) return;
//this.original_x = Raphael.parseTransformString(this.attr("transform"))[0][1];
//this.original_y = Raphael.parseTransformString(this.attr("transform"))[0][2];
this.animate({r: 70, opacity: 0.25}, 500, ">");
this.updated_x = this.original_x;
this.updated_y = this.original_y;
};
this.move = function(dx, dy) {
//var ts = Raphael.parseTransformString(this.attr("transform"));
this.updated_x = this.original_x + dx;
this.updated_y = this.original_y + dy;
//ts[0][1] = this.original_x + dx;
//ts[0][2] = this.original_y + dy;
this.attr({transform: 't' + this.updated_x + ',' + this.updated_y});
};
this.up = function() {
if(confirm("Shall I update the new position??")) {
this.original_x = this.updated_x;
this.original_y = this.updated_y;
}
var transformString = "t" + this.original_x + "," + this.original_y;
this.attr("transform", transformString);
this.attr({fill: "#fff"});
this.animate({r: 50, opacity: 1}, 500, ">");
};
找到了一个有趣的解决方法:如果在 this.original_x 和 this.original_y 中都添加一个 epsilon,则可以避免这种情况。如果 this.original_x 和 this.original_y 与起始坐标不完全相同,问题似乎就会消失。查看:http://jsfiddle.net/6ozsfdaf/13/
this.up = function() {
var ts;
this.original_x += 0.0000000001;
this.original_y += 0.0000000001;
var transformString = "t" + this.original_x + "," + this.original_y;
this.attr("transform", transformString);
console.log("transformString: " + transformString);
console.log("transformAttrib: " + this.attr("transform"));
this.attr({fill: "#fff"});
this.animate({r: 50, opacity: 1}, 500, ">");
};
编辑
发现了问题。在 Raphael 中,Raphael.parseTransformString() 的输出被缓存和重用。在您的 move() 方法中,您修改了 Raphael.parseTransformString() 的输出,当您为它提供相同的字符串时,Raphael 会尝试使用您修改后的数组。当注册第一个 drag() 事件时会发生这种情况。您要求它解析当前位置,然后用新位置更新数组的输出数组。然后,稍后,当 this.up() 被调用时,您为 Raphael.parseTransformString() 提供相同的字符串。 Raphael 然后使用您修改的数组数组。这是固定的fiddle:http://jsfiddle.net/6ozsfdaf/16/
这里是代码(每次移动时使用新的数组数组进行转换):
this.move = function(dx, dy) {
var ts = [];
ts.push(new Array('t'));
ts[0][1] = this.original_x + dx;
ts[0][2] = this.original_y + dy;
this.attr({transform: ts.toString()});
};
我正在使用 Raphael.js 实现拖放系统。为此,我将原始的 x 和 y 位置存储在 mousedown 上,如果在 mouseup 上发生碰撞,我想将位置重置为原始位置。这是执行重置的代码("this" 指的是这里的 raphael 对象):
var transformString = "t" + this.original_x + "," + this.original_y;
this.attr("transform", transformString);
奇怪的是,设置属性后,转换字符串改变了几个像素。我调试了这个:
var transformString = "t" + this.original_x + "," + this.original_y;
this.attr("transform", transformString);
console.log("transformString: " + transformString);
console.log("transformAttrib: " + this.attr("transform"));
据我所知,在任何情况下,两个记录的值都应该相等。但它们有时会相差 20 像素。有人知道这里发生了什么吗?
E:这是一个简化版本,没有碰撞测试,仍然重现了错误:http://jsfiddle.net/6ozsfdaf
我不太确定为什么会出现这个问题,但我想知道这是否是更好的解决方案。与其每次都解析字符串,不如存储转换并使用它。
我也将其切换为使用 transform() 方法,而不是 attr(transform:..) 方法。虽然我认为这通常会起作用,但它在逻辑上不太正确,因为 SVG 属性不采用 Raphael 转换字符串,但我认为 Raph 会拦截并处理它(但可能更容易出错)。
在转换字符串中还值得牢记,'t' 是相对转换而 'T' 是绝对转换(我认为这不是问题,因为没有前面的转换,但我想知道它是否也相关)。
this.start = function() {
if (this.reference.static) return;
this.original_t = this.transform();
this.animate({r: 70, opacity: 0.25}, 500, ">");
};
this.move = function(dx, dy) {
this.transform( this.original_t + 't' + dx + ',' + dy);
};
this.up = function() {
this.transform( this.original_t );
console.log("transformString: " + this.original_t);
console.log("transformAttrib: " + this.transform());
this.attr({fill: "#fff"});
this.animate({r: 50, opacity: 1}, 500, ">");
};
我不确定为什么会这样。我什至尝试使用 onmousedown
事件在 onstart
之前捕获坐标,即使那样也没有用。 Raphael 提供的使用 getBBox()
获取坐标的不同方法,直接访问 x
和 y
,也没有帮助。
所以我的想法是,我们应该手动维护和跟踪坐标。所以我使用了你的 original_x
和 original_y
变量,它们在你创建并设置了一些转换值之后捕获了 <path>
的位置。下面是相同的代码
这是工作 fiddle。
this.raph = R.path(svgPath).attr({
stroke: "hsb(0, 1, 1)",
fill: "#fff",
opacity: 1.0,
cx: 100,
cy: 900
}).transform("t" + x + "," + y);
this.raph.original_x = x;
this.raph.original_y = y;
//comment the lines in start method which captures original_x and original_y
//this.original_x = Raphael.parseTransformString(this.attr("transform"))[0][1];
//this.original_y = Raphael.parseTransformString(this.attr("transform"))[0][2];
有关跟踪坐标的更多信息:
我们还会有一个坐标 updated_x
和 updated_y
,它们将在 move
方法中更新。 onFinish/onUp 方法,我们可以检查是否应该更新新位置。在这里,它只是询问是否应该更新新位置,并根据我们的输入设置最终结果。
检查这个 fiddle:
this.start = function() {
if (this.reference.static) return;
//this.original_x = Raphael.parseTransformString(this.attr("transform"))[0][1];
//this.original_y = Raphael.parseTransformString(this.attr("transform"))[0][2];
this.animate({r: 70, opacity: 0.25}, 500, ">");
this.updated_x = this.original_x;
this.updated_y = this.original_y;
};
this.move = function(dx, dy) {
//var ts = Raphael.parseTransformString(this.attr("transform"));
this.updated_x = this.original_x + dx;
this.updated_y = this.original_y + dy;
//ts[0][1] = this.original_x + dx;
//ts[0][2] = this.original_y + dy;
this.attr({transform: 't' + this.updated_x + ',' + this.updated_y});
};
this.up = function() {
if(confirm("Shall I update the new position??")) {
this.original_x = this.updated_x;
this.original_y = this.updated_y;
}
var transformString = "t" + this.original_x + "," + this.original_y;
this.attr("transform", transformString);
this.attr({fill: "#fff"});
this.animate({r: 50, opacity: 1}, 500, ">");
};
找到了一个有趣的解决方法:如果在 this.original_x 和 this.original_y 中都添加一个 epsilon,则可以避免这种情况。如果 this.original_x 和 this.original_y 与起始坐标不完全相同,问题似乎就会消失。查看:http://jsfiddle.net/6ozsfdaf/13/
this.up = function() {
var ts;
this.original_x += 0.0000000001;
this.original_y += 0.0000000001;
var transformString = "t" + this.original_x + "," + this.original_y;
this.attr("transform", transformString);
console.log("transformString: " + transformString);
console.log("transformAttrib: " + this.attr("transform"));
this.attr({fill: "#fff"});
this.animate({r: 50, opacity: 1}, 500, ">");
};
编辑 发现了问题。在 Raphael 中,Raphael.parseTransformString() 的输出被缓存和重用。在您的 move() 方法中,您修改了 Raphael.parseTransformString() 的输出,当您为它提供相同的字符串时,Raphael 会尝试使用您修改后的数组。当注册第一个 drag() 事件时会发生这种情况。您要求它解析当前位置,然后用新位置更新数组的输出数组。然后,稍后,当 this.up() 被调用时,您为 Raphael.parseTransformString() 提供相同的字符串。 Raphael 然后使用您修改的数组数组。这是固定的fiddle:http://jsfiddle.net/6ozsfdaf/16/
这里是代码(每次移动时使用新的数组数组进行转换):
this.move = function(dx, dy) {
var ts = [];
ts.push(new Array('t'));
ts[0][1] = this.original_x + dx;
ts[0][2] = this.original_y + dy;
this.attr({transform: ts.toString()});
};