【问题标题】:Raphael.js attr function sets wrong valueRaphael.js attr 函数设置错误的值
【发布时间】:2015-12-20 16:58:32
【问题描述】:

我正在使用 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"));

AFAIK,两个记录的值在任何情况下都应该相等。但它们有时会相差 20 像素。有谁知道这里发生了什么?

E:这里是简化版,没有碰撞测试,依旧重现bug:http://jsfiddle.net/6ozsfdaf

【问题讨论】:

  • 你能为此创建示例 jsfiddle 并分享吗?
  • 是的,这是一个简化版,没有碰撞测试,仍然重现错误:jsfiddle.net/6ozsfdaf

标签: javascript svg raphael


【解决方案1】:

我不确定为什么会这样。我什至尝试使用onmousedown 事件在onstart 之前捕获坐标,即使那样也没有用。 Raphael 还提供了不同的方法来使用getBBox() 获取坐标,直接访问xy,没有帮助。

所以我的想法是,我们应该手动维护和跟踪坐标。因此,我使用了您的 original_xoriginal_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_xupdated_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, ">");
};

【讨论】:

  • 这是一个很好的临时解决方案,但仍然无法完全发挥作用。在你的小提琴中,如果你第一次非常快速地拉物体,你仍然可以将它的位置改变大约 20-30px。
  • 我尝试了很多次,拉物体,但也没有发现小的差异。你的意思是在纸外/窗外?如果是这种情况,它只是等待鼠标指针进入纸张内部,最后在点击时它会回到最初的位置。
【解决方案2】:

我不太确定为什么会出现这个问题,但我想知道这是否可能是一个更好的解决方案。而不是每次都解析字符串,只需存储转换并使用它。

我还将它切换为使用 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, ">");
};

jsfiddle

【讨论】:

    【解决方案3】:

    找到了一个有趣的解决方法:如果您在 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 使用您修改后的数组。这是固定的小提琴: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()});
    };
    

    【讨论】:

      猜你喜欢
      • 2019-08-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多