Reputation: 13
TL;DR: event that should be fired on element drag is being fired on element click.
I'm using svg.draggable.js and it has 4 custom events, the ones important here are dragstart
and dragmove
. dragstart
fires when the user clicks the element, while dragmove
fires on every update on the element position. The problem is that dragmove
is fired when the element is clicked too, therefore running logic that it should not (well, at least in my case).
I've already searched on how to stop an event from firing and got to preventDefaul()
, stopPropagation()
and stopImmediatePropagation()
but none of these solves my problem.
Is there a way to make an event prevent another event from firing?
P.S: there's an open issue on the repository, but I'm trying to find an "agnostic" way to do this.
What should happen on click:
// start dragging
DragHandler.prototype.start = function(e){
// check for left button
if(e.type == 'click'|| e.type == 'mousedown' || e.type == 'mousemove'){
if((e.ctrlKey || e.metaKey)/*if Ctrl or cmd key pressed, then Multi Select*/ || (e.which || e.buttons) != 1){
return;
}
}
var _this = this;
// fire beforedrag event
this.el.fire('beforedrag', { event: e, handler: this });
// search for parent on the fly to make sure we can call
// draggable() even when element is not in the dom currently
this.parent = this.parent || this.el.parent(SVG.Nested) || this.el.parent(SVG.Doc);
this.p = this.parent.node.createSVGPoint();
// save current transformation matrix
this.m = this.el.node.getScreenCTM().inverse();
var box = this.getBBox();
var anchorOffset = 0;
var anchorOffsetVertical = 0;
// fix text-anchor in text-element (#37)
if(this.el instanceof SVG.Text) {
var tChildren = this.el.node.children;
if (tChildren && tChildren.length) {
for(var i = 0; i < tChildren.length; i++) {
var currentOffset = tChildren[i].getComputedTextLength();
if (currentOffset > anchorOffset) {
anchorOffset = currentOffset;
}
}
} else {
anchorOffset = this.el.node.getComputedTextLength();
}
switch(this.el.node.style.textAnchor || this.el.attr('text-anchor')){
case 'middle':
anchorOffset /= 2;
break;
case 'start':
anchorOffset = 0;
break;
}
}
this.startPoints = {
// We take absolute coordinates since we are just using a delta here
point: this.transformPoint(e),
box: box,
offset: anchorOffset
};
// add drag and end events to window
SVG.on(window, 'mousemove.drag', function(e){ _this.drag(e); });
SVG.on(window, 'touchmove.drag', function(e){ _this.drag(e); });
SVG.on(window, 'mouseup.drag', function(e){ _this.end(e); });
SVG.on(window, 'touchend.drag', function(e){ _this.end(e); });
// fire dragstart event
this.el.fire('dragstart', {event: e, p: this.p, m: this.m, handler: this});
// prevent browser drag behavior
e.preventDefault();
};
What should happen while dragging the element:
// while dragging
DragHandler.prototype.drag = function(e){
var box = this.getBBox(),
p = this.transformPoint(e),
x = this.startPoints.box.x + (p.x - this.startPoints.point.x) + this.startPoints.offset,
y = this.startPoints.box.y + (p.y - this.startPoints.point.y),
c = this.constraint,
s = this.el.transform().matrix.a;
this.el.fire('dragmove', { event: e, p: this.p, m: this.m, handler: this });
// move the element to its new position, if possible by constraint
if (typeof c == 'function') {
var coord = c.call(this.el, x, y, this.m);
if (typeof coord == 'boolean') {
coord = {
x: coord,
y: coord
};
}
// if true, we just move. If !false its a number and we move it there
if (coord.x === true) {
this.el.x(x);
} else if (coord.x !== false) {
this.el.x(coord.x);
}
if (coord.y === true) {
this.el.y(y);
} else if (coord.y !== false) {
this.el.y(coord.y);
}
} else if (typeof c == 'object') {
// keep element within constrained box
if (c.minX !== null && x < c.minX)
x = c.minX;
else if (c.maxX !== null && x > c.maxX - box.width){
x = c.maxX - box.width;
}if (c.minY !== null && y < c.minY)
y = c.minY;
else if (c.maxY !== null && y > c.maxY - box.height)
y = c.maxY - box.height;
this.el.move(x, y);
// console.log(x, y, s);
}
};
There's a bit of own code on these snippets but in general it is from svg.draggable.js
Upvotes: 1
Views: 2085
Reputation: 7413
This is how I've solved this problem;
function onMouse(shape, dragCB, clickCB){
var mousestate = 0;
shape.on( 'mousedown', function() {
mousestate = 1;
});
shape.on( 'mousemove', function() {
if(mousestate === 1) mousestate = 2;
});
shape.on( 'mouseup', function(e) {
if(mousestate === 2) {
dragCB(e);
}else{
clickCB(e)
}
mousestate = 0;
});
}
Upvotes: 0
Reputation: 249
One way I imagine to get around that is to define a flag that is set to true when dragstart
is invoked, then inside dragmove
handler you clear that flag the first time (so the logic is not invoked when the element is clicked).
So inside the dragmove
handler you define something like:
if(flag) {
flag = false;
return
}
else {
// your logic for dragmove here
}
Upvotes: 1