I\'m implementing a drag and drop system with Raphael.js. For this, i\'m storing the original x and y position on mousedown, and if there is a collision on mouseup, I want to re
I'm not sure why this is happening. I tried even capturing the co-ordinates before onstart
using onmousedown
event, even that didnt work. Also different methods provided by Raphael to get the co-ordinates using getBBox()
, accessing x
and y
directly, didnt help.
So what I thought is, we should Maintain and Track the coordinates manually. So I have used your original_x
and original_y
variables which captures the position of the <path>
after you create and set with some transform value. Below is the code of the same
Here is the working 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];
More info regarding tracking the co-ordinates:
We will have one more coordinate say updated_x
and updated_y
, which will be updated in the move
method. onFinish/onUp method, we can have the check whether we should update the new position or not. Here, it just asks whether new position should be updated or not and based on our input, it sets the final result.
Check this 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, ">");
};
I'm not quite sure why that problem happens yet, but I'm wondering if this may be a better solution anyway. Rather than parsing the strings each time, just store the transform and use that.
I've also switched it to use the transform() method, rather than the attr(transform:..) method. Whilst I think that would normally work, its not quite right logically, as SVG attributes don't take a Raphael transform string, but I assume Raph would intercept that and deal with it (but maybe more error prone).
Its also worth bearing in mind in a transform string that 't' is a relative transform and 'T' is an absolute transform (I don't think thats the issue as there's no preceding transform, but I was wondering if its also related).
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
Found an interesting fix: you can avoid the situation if you add an epsilon to both this.original_x and this.original_y. The problem seems to disappear if this.original_x and this.original_y are not exactly the same as the starting coordinates. Check out: 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, ">");
};
EDIT Found the problem. In Raphael, Raphael.parseTransformString()'s output is cached and reused. In your move() method, you modify the output of Raphael.parseTransformString(), and Raphael tries to use your modified array when you supply it with the same string. This happens when the first drag() event is registered. You ask it to parse the current place, and then update the output array of arrays with the new location. And then, way later, when this.up() is called, you supply the Raphael.parseTransformString() with the same string. Raphael then uses your modified array of arrays. This is the fixed fiddle: http://jsfiddle.net/6ozsfdaf/16/
And here is the code (use a new array of arrays to transform when moved each time):
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()});
};