问题
Using Raphael, I wish to be able to drag a shape (an ellipse in the example below) containing a text object, dragging either the shape or the text. I hoped to do this by setting the functions passed to the text element's drag()
method to delegate to the associated shape (trying a more polymorphic approach to this other one). However, this results in an error "obj.addEventListener is not a function" when text.drag(...)
is called.
I'm new to javascript, so I've probably made a really obvious blunder, but I can't spot it. Have I misused call()
in my delegating functions moveText
, dragText
, and upText
? Or is this a Raphael thing? Any help would be greatly appreciated.
<html>
<head>
<title>Raphael delegated drag test</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script src="js/raphael.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<script type="text/javascript">
window.onload = function initPage() {
'use strict';
var paper = Raphael("holder", 640, 480);
var shape = paper.ellipse(190,100,30, 20).attr({
fill: "green",
stroke: "green",
"fill-opacity": 0,
"stroke-width": 2,
cursor: "move"
});
var text = paper.text(190,100,"Ellipse").attr({
fill: "green",
stroke: "none",
cursor: "move"
});
// Associate the shape and text elements with each other
shape.text = text;
text.shape = shape;
// Drag start
var dragShape = function () {
this.ox = this.attr("cx");
this.oy = this.attr("cy");
}
var dragText = function () {
dragShape.call(this.shape);
}
// Drag move
var moveShape = function (dx, dy) {
this.attr({cx: this.ox + dx, cy: this.oy + dy});
this.text.attr({x: this.ox + dx, y: this.oy + dy});
}
var moveText = function (dx,dy) {
moveShape.call(this.shape,dx,dy);
}
// Drag release
var upShape = function () {
}
var upText = function () {
upShape.call(this.shape);
}
shape.drag(moveShape, dragShape, upShape);
text.drag(moveText, dragText, upText);
};
</script>
<div id="holder"></div>
</body>
</html>
Solution
As pointed out in this answer, the problem arises from the choice of the attribute names:
// Associate the shape and text elements with each other
shape.text = text;
text.shape = shape;
Changing these to more verbose names (and less likely to conflict with Raphael) makes the problem go away, but it's safer to set them as data attributes :
// Associate the shape and text elements with each other
shape.data("enclosedText",text);
text.data("parentShape",shape);
// Drag start
var dragShape = function () {
this.ox = this.attr("cx");
this.oy = this.attr("cy");
}
var dragText = function () {
dragShape.call(this.data("parentShape"));
}
// Drag move
var moveShape = function (dx, dy) {
this.attr({cx: this.ox + dx, cy: this.oy + dy});
this.data("enclosedText").attr({x: this.ox + dx, y: this.oy + dy});
}
var moveText = function (dx,dy) {
moveShape.call(this.data("parentShape"),dx,dy);
}
回答1:
// Associate the shape and text elements with each other
shape.text = text;
text.shape = shape;
You are adding attributes to Raphael objects. Without knowing how Raphael works (or will work in the future) this is dangerous and apparently also what's causing the problem. If you really want to associate them i recommend using Raphaels Element.data
: http://raphaeljs.com/reference.html#Element.data
来源:https://stackoverflow.com/questions/8830330/delegating-drag-function-in-raphael